codex-1up 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  - ✅ Unified **Codex config** with multiple profiles: `balanced` / `safe` / `minimal` / `yolo`
12
12
  - ✅ 🔊 **Notification sounds** with customizable audio alerts for Codex events
13
13
 
14
+ ![Screenshot of Codex 1UP terminal interface] (https://raw.githubusercontent.com/regenrek/codex-1up/main/public/example.png)
14
15
 
15
16
  ## Quick start
16
17
 
package/dist/main.js CHANGED
@@ -1,31 +1,31 @@
1
- import{runMain as Ft}from"citty";import{defineCommand as Ot}from"citty";import{defineCommand as ft}from"citty";import{fileURLToPath as ct}from"url";import{dirname as dt,resolve as N}from"path";import{promises as U}from"fs";import*as L from"os";import{accessSync as Fe}from"fs";import*as Le from"toml";import*as p from"@clack/prompts";import{which as G,$ as x}from"zx";import rt from"fs-extra";import*as re from"path";import*as De from"os";import{createWriteStream as Ke}from"fs";function de(e){let t=null;try{t=Ke(e,{flags:"a"})}catch{}let o=(i,n)=>{let r=i?`${i} ${n}
2
- `:`${n}
3
- `;process.stdout.write(r),t&&t.write(r)};return{log:i=>o("",i),info:i=>o("",i),ok:i=>o("\u2714",i),warn:i=>o("\u26A0",i),err:i=>o("\u2716",i)}}import{$ as F}from"zx";import{which as Ye}from"zx";import{spawn as Qe}from"child_process";async function d(e){try{return await Ye(e),!0}catch{return!1}}async function ue(){return await d("brew")?"brew":await d("apt-get")?"apt":await d("dnf")?"dnf":await d("pacman")?"pacman":await d("zypper")?"zypper":"none"}async function m(e,t,o={dryRun:!1}){if(o.dryRun){let n=[e,...t].map(r=>r.includes(" ")?`"${r}"`:r).join(" ");o.logger?.log(`[dry-run] ${n}`);return}let i=Qe(e,t,{stdio:"inherit",cwd:o.cwd||process.cwd(),shell:!1});await new Promise((n,r)=>{i.on("error",r),i.on("exit",s=>{if(s===0)return n();r(new Error(`Command failed (${s}): ${e} ${t.join(" ")}`))})})}function D(e){let t=new Date().toISOString().replace(/[:.]/g,"-").slice(0,-5);return`${e}.backup.${t}`}import ge from"fs-extra";import*as q from"path";import*as W from"os";async function me(e){let t=await d("node"),o=await d("npm");if(t&&o){let n=(await F`node -v`).stdout.trim();e.logger.ok(`Node.js present (${n})`);return}switch(e.options.installNode){case"nvm":await Ze(e);break;case"brew":await et(e);break;case"skip":e.logger.warn("Skipping Node installation; please install Node 18+ manually");return}if(await d("node")){let n=(await F`node -v`).stdout.trim();e.logger.ok(`Node.js installed (${n})`)}else throw e.logger.err("Node installation failed"),new Error("Node.js installation failed")}async function Ze(e){if(e.logger.info("Installing Node.js via nvm"),e.options.dryRun){e.logger.log("[dry-run] install nvm + Node LTS");return}let t=q.join(e.homeDir,".nvm"),o=q.join(t,"nvm.sh");await ge.pathExists(t)||(e.logger.info("Installing nvm..."),await F`bash -c "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash"`);let i=`export NVM_DIR="${t}" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && nvm install --lts`;await F`bash -c ${i}`}async function et(e){if(e.logger.info("Installing Node.js via Homebrew"),!await d("brew"))if(W.platform()==="darwin"){if(e.logger.info("Homebrew not found; installing Homebrew"),e.options.dryRun){e.logger.log("[dry-run] install Homebrew");return}await F`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`;let t=W.platform()==="darwin"&&W.arch()==="arm64"?"/opt/homebrew/bin/brew":"/usr/local/bin/brew";if(await ge.pathExists(t)){let o=q.dirname(t);process.env.PATH=`${o}:${process.env.PATH||""}`;try{let n=(await F`${t} shellenv`).stdout.trim().match(/export PATH="([^"]+)"/);n&&(process.env.PATH=`${n[1]}:${process.env.PATH||""}`)}catch{}}}else throw new Error("Homebrew is only available on macOS");await m("brew",["install","node"],{dryRun:e.options.dryRun,logger:e.logger})}import{$ as oe}from"zx";var tt=["@openai/codex","@ast-grep/cli"];async function we(e){e.logger.info("Checking global npm packages (@openai/codex, @ast-grep/cli)");let t=[];for(let o of tt)try{let n=(await oe`npm view ${o} version`.quiet()).stdout.trim();if(!n){e.logger.warn(`Could not fetch latest version for ${o}; skipping upgrade check`);continue}let r=await oe`npm ls -g ${o} --depth=0 --json`.quiet().nothrow(),s="";try{s=JSON.parse(r.stdout||"{}").dependencies?.[o]?.version||""}catch{s=""}s?s!==n?(e.logger.info(`${o} ${s} -> ${n}`),t.push(`${o}@${n}`)):e.logger.ok(`${o} up-to-date (${s})`):(e.logger.info(`${o} not installed; will install @${n}`),t.push(`${o}@${n}`))}catch(i){e.logger.warn(`Error checking ${o}: ${i}`);let n=await oe`npm ls -g ${o} --depth=0 --json`.quiet().nothrow(),r="";try{r=JSON.parse(n.stdout||"{}").dependencies?.[o]?.version||""}catch{r=""}r||t.push(o)}t.length>0?(e.logger.info("Installing/updating global npm packages"),await m("npm",["install","-g",...t],{dryRun:e.options.dryRun,logger:e.logger})):e.logger.ok("Global npm packages are up-to-date"),await d("codex")?e.logger.ok("Codex CLI installed"):e.logger.err("Codex CLI not found after install"),await d("ast-grep")?e.logger.ok("ast-grep installed"):e.logger.warn("ast-grep not found; check npm global path")}import{$ as ot}from"zx";import*as ie from"path";import ne from"fs-extra";var nt={brew:["fd","ripgrep","fzf","jq","yq","difftastic"],apt:["ripgrep","fzf","jq","yq","git-delta"],dnf:["ripgrep","fd-find","fzf","jq","yq","git-delta"],pacman:["ripgrep","fd","fzf","jq","yq","git-delta"],zypper:["ripgrep","fd","fzf","jq","yq","git-delta"],none:[]};async function he(e){let t=await ue();if(e.logger.info(`Detected package manager: ${t}`),t==="none"){e.logger.warn("Could not detect a supported package manager; please install tools manually");return}let o=nt[t]||[];if(o.length>0)switch(t){case"brew":await m("brew",["update"],{dryRun:e.options.dryRun,logger:e.logger}),await m("brew",["install",...o],{dryRun:e.options.dryRun,logger:e.logger});break;case"apt":await m("sudo",["apt-get","update","-y"],{dryRun:e.options.dryRun,logger:e.logger}),await m("sudo",["apt-get","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{}),await d("fd")||await m("sudo",["apt-get","install","-y","fd-find"],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"dnf":await m("sudo",["dnf","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"pacman":await m("sudo",["pacman","-Sy","--noconfirm",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"zypper":await m("sudo",["zypper","refresh"],{dryRun:e.options.dryRun,logger:e.logger}),await m("sudo",["zypper","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break}if(!await d("difft")&&!await d("difftastic")&&(await d("cargo")?(e.logger.info("Installing difftastic via cargo"),await m("cargo",["install","difftastic"],{dryRun:e.options.dryRun,logger:e.logger})):e.logger.warn("difftastic not found and Rust/cargo missing; falling back to git-delta")),await d("fdfind")&&!await d("fd")){let n=ie.join(e.homeDir,".local","bin");await ne.ensureDir(n);let r=(await ot`command -v fdfind`).stdout.trim(),s=ie.join(n,"fd");await ne.pathExists(s)||(e.options.dryRun?e.logger.log(`[dry-run] ln -s ${r} ${s}`):await ne.symlink(r,s),e.logger.ok("fd alias created at ~/.local/bin/fd"))}let i=["fd","fdfind","rg","fzf","jq","yq","difft","difftastic","delta","ast-grep"];for(let n of i)await d(n)&&e.logger.ok(`${n} \u2713`)}import I from"fs-extra";import*as B from"path";async function be(e){let t=B.join(e.homeDir,".codex","config.toml"),o=B.join(e.rootDir,"templates","codex-config.toml");if(await I.ensureDir(B.dirname(t)),!await I.pathExists(o))throw e.logger.err(`Unified config template missing at ${o}`),new Error(`Template not found: ${o}`);if(!await I.pathExists(t)){e.logger.info(`Creating unified Codex config with multiple profiles at ${t}`),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):await I.copy(o,t),e.logger.ok("Created ~/.codex/config.toml"),await ye(t,e.options.profile,e),e.logger.info("Tip: use 'codex --profile <name>' to switch at runtime or 'codex-1up config set-profile <name>' to persist.");return}e.logger.warn("~/.codex/config.toml already exists");let i=e.options.overwriteConfig;if(i==="no"){e.logger.info("Keeping existing config unchanged");return}let n=!1;if(i==="yes")n=!0;else if(!e.options.assumeYes&&!e.options.skipConfirmation){n=!1,e.logger.info("Keeping existing config; you can manage profiles via the new CLI later.");return}if(n){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await I.copy(t,r),e.logger.info(`Backed up to ${r}`),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):await I.copy(o,t),e.logger.ok("Overwrote ~/.codex/config.toml with unified template"),await ye(t,e.options.profile,e)}}async function ye(e,t,o){if(o.logger.info(`Setting active profile to: ${t}`),o.options.dryRun){o.logger.log(`[dry-run] set profile = "${t}" in ${e}`);return}let n=(await I.readFile(e,"utf8")).split(`
4
- `),r=!1,s=n.map(a=>/^\s*profile\s*=/.test(a)?(r=!0,`profile = "${t}"`):a);r||s.unshift(`profile = "${t}"`),await I.writeFile(e,s.join(`
5
- `),"utf8")}import E from"fs-extra";import*as _ from"path";async function $e(e){let t=_.join(e.homeDir,".codex","notify.sh"),o=_.join(e.rootDir,"templates","notification.sh");await E.ensureDir(_.dirname(t));let i=e.options.notify;if(i==="no"){e.logger.info("Skipping notify hook installation");return}if(!await E.pathExists(o)){e.logger.warn(`Notification template missing at ${o}; skipping notify hook install`);return}if(await E.pathExists(t))if(i==="yes"){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await E.copy(t,r),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):(await E.copy(o,t),await E.chmod(t,493)),e.logger.ok("Updated notify hook (backup created)")}else!e.options.assumeYes&&!e.options.skipConfirmation&&e.logger.info("Keeping existing notify hook");else e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):(await E.copy(o,t),await E.chmod(t,493)),e.logger.ok("Installed notify hook to ~/.codex/notify.sh");let n=_.join(e.homeDir,".codex","config.toml");await E.pathExists(n)?await it(n,t,e):e.logger.warn(`Config not found at ${n}; run again after config is created`)}async function it(e,t,o){if(o.options.dryRun){o.logger.log("[dry-run] update config notify and tui.notifications");return}let n=(await E.readFile(e,"utf8")).split(/\r?\n/),r="",s=null,a=null,c=!1,R=!1;for(let l=0;l<n.length;l++){let f=n[l],k=f.match(/^\s*\[([^\]]+)\]\s*$/);if(k){r=k[1],r==="tui"&&(a=l);continue}let g=/^\s*notify\s*=\s*\[/.test(f),A=/^\s*tui\.notifications\s*=/.test(f),j=/^\s*notifications\s*=/.test(f);g&&(r===""?s===null&&(s=l):/^profiles\.[^.]+\.features$/.test(r)&&(n.splice(l,1),l--,c=!0)),A&&/^profiles\.[^.]+\.features$/.test(r)&&(n.splice(l,1),l--,R=!0),j&&r===""&&(n.splice(l,1),l--,R=!0)}function $(l){let f=0;for(;f<n.length&&/^\s*(#.*)?$/.test(n[f]);)f++;n.splice(f,0,l)}if(s!==null){let l=n[s].match(/^(\s*notify\s*=\s*\[)([^\]]*)\]/);if(l){let f=l[2].trim();if(!f.includes(JSON.stringify(t))){let g=f&&!f.endsWith(",")?", ":"";n[s]=`${l[1]}${f}${g}${JSON.stringify(t)}]`,o.logger.ok("Added notify hook to config")}}}else $(`notify = [${JSON.stringify(t)}]`),o.logger.ok("Enabled notify hook in config");let w=!1;if(a!==null){let l=a+1,f=!1;for(;l<n.length;l++){let k=n[l];if(/^\s*\[/.test(k))break;if(/^\s*notifications\s*=/.test(k)){n[l]="notifications = true",f=!0,w=!0;break}}f||(n.splice(a+1,0,"notifications = true"),w=!0)}w||$(`[tui]
6
- notifications = true`);let S=[];r="";for(let l=0;l<n.length;l++){let f=n[l],k=f.match(/^\s*\[([^\]]+)\]\s*$/);if(k){r=k[1],S.push(f);continue}/^\s*tui\.notifications\s*=/.test(f)||/^\s*notifications\s*=/.test(f)&&r!=="tui"||S.push(f)}await E.writeFile(e,S.join(`
7
- `),"utf8")}import v from"fs-extra";import*as u from"path";async function Ce(e){let t=u.join(e.rootDir,"sounds"),o=u.join(e.homeDir,".codex","sounds");await v.ensureDir(o);let i=e.options.notificationSound;if(i==="none"){let w=await ke(e);e.options.dryRun?e.logger.log(`[dry-run] update ${w}`):await ve(w,`# Notification sound (disabled)
1
+ import{runMain as Ft}from"citty";import{defineCommand as Ot}from"citty";import{defineCommand as st}from"citty";import{fileURLToPath as lt}from"url";import{dirname as pt,resolve as N}from"path";import{promises as U}from"fs";import*as L from"os";import{accessSync as ft}from"fs";import*as _e from"toml";import*as p from"@clack/prompts";import{which as G,$ as x}from"zx";import tt from"fs-extra";import*as re from"path";import*as De from"os";import{createWriteStream as He}from"fs";function de(e){let t=null;try{t=He(e,{flags:"a"})}catch{}let o=(n,i)=>{let r=n?`${n} ${i}
2
+ `:`${i}
3
+ `;process.stdout.write(r),t&&t.write(r)};return{log:n=>o("",n),info:n=>o("",n),ok:n=>o("\u2714",n),warn:n=>o("\u26A0",n),err:n=>o("\u2716",n)}}import{$ as O}from"zx";import{which as xe}from"zx";import{spawn as Je}from"child_process";async function d(e){try{return await xe(e),!0}catch{return!1}}async function ue(){return await d("brew")?"brew":await d("apt-get")?"apt":await d("dnf")?"dnf":await d("pacman")?"pacman":await d("zypper")?"zypper":"none"}async function m(e,t,o={dryRun:!1}){if(o.dryRun){let i=[e,...t].map(r=>r.includes(" ")?`"${r}"`:r).join(" ");o.logger?.log(`[dry-run] ${i}`);return}let n=Je(e,t,{stdio:"inherit",cwd:o.cwd||process.cwd(),shell:!1});await new Promise((i,r)=>{n.on("error",r),n.on("exit",s=>{if(s===0)return i();r(new Error(`Command failed (${s}): ${e} ${t.join(" ")}`))})})}function D(e){let t=new Date().toISOString().replace(/[:.]/g,"-").slice(0,-5);return`${e}.backup.${t}`}import ge from"fs-extra";import*as q from"path";import*as W from"os";async function me(e){let t=await d("node"),o=await d("npm");if(t&&o){let i=(await O`node -v`).stdout.trim();e.logger.ok(`Node.js present (${i})`);return}switch(e.options.installNode){case"nvm":await Xe(e);break;case"brew":await Ke(e);break;case"skip":e.logger.warn("Skipping Node installation; please install Node 18+ manually");return}if(await d("node")){let i=(await O`node -v`).stdout.trim();e.logger.ok(`Node.js installed (${i})`)}else throw e.logger.err("Node installation failed"),new Error("Node.js installation failed")}async function Xe(e){if(e.logger.info("Installing Node.js via nvm"),e.options.dryRun){e.logger.log("[dry-run] install nvm + Node LTS");return}let t=q.join(e.homeDir,".nvm"),o=q.join(t,"nvm.sh");await ge.pathExists(t)||(e.logger.info("Installing nvm..."),await O`bash -c "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash"`);let n=`export NVM_DIR="${t}" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && nvm install --lts`;await O`bash -c ${n}`}async function Ke(e){if(e.logger.info("Installing Node.js via Homebrew"),!await d("brew"))if(W.platform()==="darwin"){if(e.logger.info("Homebrew not found; installing Homebrew"),e.options.dryRun){e.logger.log("[dry-run] install Homebrew");return}await O`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`;let t=W.platform()==="darwin"&&W.arch()==="arm64"?"/opt/homebrew/bin/brew":"/usr/local/bin/brew";if(await ge.pathExists(t)){let o=q.dirname(t);process.env.PATH=`${o}:${process.env.PATH||""}`;try{let i=(await O`${t} shellenv`).stdout.trim().match(/export PATH="([^"]+)"/);i&&(process.env.PATH=`${i[1]}:${process.env.PATH||""}`)}catch{}}}else throw new Error("Homebrew is only available on macOS");await m("brew",["install","node"],{dryRun:e.options.dryRun,logger:e.logger})}import{$ as oe}from"zx";var Ye=["@openai/codex","@ast-grep/cli"];async function we(e){e.logger.info("Checking global npm packages (@openai/codex, @ast-grep/cli)");let t=[];for(let o of Ye)try{let i=(await oe`npm view ${o} version`.quiet()).stdout.trim();if(!i){e.logger.warn(`Could not fetch latest version for ${o}; skipping upgrade check`);continue}let r=await oe`npm ls -g ${o} --depth=0 --json`.quiet().nothrow(),s="";try{s=JSON.parse(r.stdout||"{}").dependencies?.[o]?.version||""}catch{s=""}s?s!==i?(e.logger.info(`${o} ${s} -> ${i}`),t.push(`${o}@${i}`)):e.logger.ok(`${o} up-to-date (${s})`):(e.logger.info(`${o} not installed; will install @${i}`),t.push(`${o}@${i}`))}catch(n){e.logger.warn(`Error checking ${o}: ${n}`);let i=await oe`npm ls -g ${o} --depth=0 --json`.quiet().nothrow(),r="";try{r=JSON.parse(i.stdout||"{}").dependencies?.[o]?.version||""}catch{r=""}r||t.push(o)}t.length>0?(e.logger.info("Installing/updating global npm packages"),await m("npm",["install","-g",...t],{dryRun:e.options.dryRun,logger:e.logger})):e.logger.ok("Global npm packages are up-to-date"),await d("codex")?e.logger.ok("Codex CLI installed"):e.logger.err("Codex CLI not found after install"),await d("ast-grep")?e.logger.ok("ast-grep installed"):e.logger.warn("ast-grep not found; check npm global path")}import{$ as Qe}from"zx";import*as ne from"path";import ie from"fs-extra";var Ze={brew:["fd","ripgrep","fzf","jq","yq","difftastic"],apt:["ripgrep","fzf","jq","yq","git-delta"],dnf:["ripgrep","fd-find","fzf","jq","yq","git-delta"],pacman:["ripgrep","fd","fzf","jq","yq","git-delta"],zypper:["ripgrep","fd","fzf","jq","yq","git-delta"],none:[]};async function he(e){let t=await ue();if(e.logger.info(`Detected package manager: ${t}`),t==="none"){e.logger.warn("Could not detect a supported package manager; please install tools manually");return}let o=Ze[t]||[];if(o.length>0)switch(t){case"brew":await m("brew",["update"],{dryRun:e.options.dryRun,logger:e.logger}),await m("brew",["install",...o],{dryRun:e.options.dryRun,logger:e.logger});break;case"apt":await m("sudo",["apt-get","update","-y"],{dryRun:e.options.dryRun,logger:e.logger}),await m("sudo",["apt-get","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{}),await d("fd")||await m("sudo",["apt-get","install","-y","fd-find"],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"dnf":await m("sudo",["dnf","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"pacman":await m("sudo",["pacman","-Sy","--noconfirm",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break;case"zypper":await m("sudo",["zypper","refresh"],{dryRun:e.options.dryRun,logger:e.logger}),await m("sudo",["zypper","install","-y",...o],{dryRun:e.options.dryRun,logger:e.logger}).catch(()=>{});break}if(!await d("difft")&&!await d("difftastic")&&(await d("cargo")?(e.logger.info("Installing difftastic via cargo"),await m("cargo",["install","difftastic"],{dryRun:e.options.dryRun,logger:e.logger})):e.logger.warn("difftastic not found and Rust/cargo missing; falling back to git-delta")),await d("fdfind")&&!await d("fd")){let i=ne.join(e.homeDir,".local","bin");await ie.ensureDir(i);let r=(await Qe`command -v fdfind`).stdout.trim(),s=ne.join(i,"fd");await ie.pathExists(s)||(e.options.dryRun?e.logger.log(`[dry-run] ln -s ${r} ${s}`):await ie.symlink(r,s),e.logger.ok("fd alias created at ~/.local/bin/fd"))}let n=["fd","fdfind","rg","fzf","jq","yq","difft","difftastic","delta","ast-grep"];for(let i of n)await d(i)&&e.logger.ok(`${i} \u2713`)}import I from"fs-extra";import*as B from"path";async function be(e){let t=B.join(e.homeDir,".codex","config.toml"),o=B.join(e.rootDir,"templates","codex-config.toml");if(await I.ensureDir(B.dirname(t)),!await I.pathExists(o))throw e.logger.err(`Unified config template missing at ${o}`),new Error(`Template not found: ${o}`);if(!await I.pathExists(t)){e.logger.info(`Creating unified Codex config with multiple profiles at ${t}`),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):await I.copy(o,t),e.logger.ok("Created ~/.codex/config.toml"),await ye(t,e.options.profile,e),e.logger.info("Tip: use 'codex --profile <name>' to switch at runtime or 'codex-1up config set-profile <name>' to persist.");return}e.logger.warn("~/.codex/config.toml already exists");let n=e.options.overwriteConfig;if(n==="no"){e.logger.info("Keeping existing config unchanged");return}let i=!1;if(n==="yes")i=!0;else if(!e.options.assumeYes&&!e.options.skipConfirmation){i=!1,e.logger.info("Keeping existing config; you can manage profiles via the new CLI later.");return}if(i){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await I.copy(t,r),e.logger.info(`Backed up to ${r}`),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):await I.copy(o,t),e.logger.ok("Overwrote ~/.codex/config.toml with unified template"),await ye(t,e.options.profile,e)}}async function ye(e,t,o){if(o.logger.info(`Setting active profile to: ${t}`),o.options.dryRun){o.logger.log(`[dry-run] set profile = "${t}" in ${e}`);return}let i=(await I.readFile(e,"utf8")).split(`
4
+ `),r=!1,s=i.map(a=>/^\s*profile\s*=/.test(a)?(r=!0,`profile = "${t}"`):a);r||s.unshift(`profile = "${t}"`),await I.writeFile(e,s.join(`
5
+ `),"utf8")}import E from"fs-extra";import*as F from"path";async function $e(e){let t=F.join(e.homeDir,".codex","notify.sh"),o=F.join(e.rootDir,"templates","notification.sh");await E.ensureDir(F.dirname(t));let n=e.options.notify;if(n==="no"){e.logger.info("Skipping notify hook installation");return}if(!await E.pathExists(o)){e.logger.warn(`Notification template missing at ${o}; skipping notify hook install`);return}if(await E.pathExists(t))if(n==="yes"){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await E.copy(t,r),e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):(await E.copy(o,t),await E.chmod(t,493)),e.logger.ok("Updated notify hook (backup created)")}else!e.options.assumeYes&&!e.options.skipConfirmation&&e.logger.info("Keeping existing notify hook");else e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${t}`):(await E.copy(o,t),await E.chmod(t,493)),e.logger.ok("Installed notify hook to ~/.codex/notify.sh");let i=F.join(e.homeDir,".codex","config.toml");await E.pathExists(i)?await et(i,t,e):e.logger.warn(`Config not found at ${i}; run again after config is created`)}async function et(e,t,o){if(o.options.dryRun){o.logger.log("[dry-run] update config notify and tui.notifications");return}let i=(await E.readFile(e,"utf8")).split(/\r?\n/),r="",s=null,a=null,c=!1,R=!1;for(let l=0;l<i.length;l++){let f=i[l],k=f.match(/^\s*\[([^\]]+)\]\s*$/);if(k){r=k[1],r==="tui"&&(a=l);continue}let g=/^\s*notify\s*=\s*\[/.test(f),T=/^\s*tui\.notifications\s*=/.test(f),A=/^\s*notifications\s*=/.test(f);g&&(r===""?s===null&&(s=l):/^profiles\.[^.]+\.features$/.test(r)&&(i.splice(l,1),l--,c=!0)),T&&/^profiles\.[^.]+\.features$/.test(r)&&(i.splice(l,1),l--,R=!0),A&&r===""&&(i.splice(l,1),l--,R=!0)}function $(l){let f=0;for(;f<i.length&&/^\s*(#.*)?$/.test(i[f]);)f++;i.splice(f,0,l)}if(s!==null){let l=i[s].match(/^(\s*notify\s*=\s*\[)([^\]]*)\]/);if(l){let f=l[2].trim();if(!f.includes(JSON.stringify(t))){let g=f&&!f.endsWith(",")?", ":"";i[s]=`${l[1]}${f}${g}${JSON.stringify(t)}]`,o.logger.ok("Added notify hook to config")}}}else $(`notify = [${JSON.stringify(t)}]`),o.logger.ok("Enabled notify hook in config");let w=!1;if(a!==null){let l=a+1,f=!1;for(;l<i.length;l++){let k=i[l];if(/^\s*\[/.test(k))break;if(/^\s*notifications\s*=/.test(k)){i[l]="notifications = true",f=!0,w=!0;break}}f||(i.splice(a+1,0,"notifications = true"),w=!0)}w||$(`[tui]
6
+ notifications = true`);let S=[];r="";for(let l=0;l<i.length;l++){let f=i[l],k=f.match(/^\s*\[([^\]]+)\]\s*$/);if(k){r=k[1],S.push(f);continue}/^\s*tui\.notifications\s*=/.test(f)||/^\s*notifications\s*=/.test(f)&&r!=="tui"||S.push(f)}await E.writeFile(e,S.join(`
7
+ `),"utf8")}import v from"fs-extra";import*as u from"path";async function Ce(e){let t=u.join(e.rootDir,"sounds"),o=u.join(e.homeDir,".codex","sounds");await v.ensureDir(o);let n=e.options.notificationSound;if(n==="none"){let w=await ke(e);e.options.dryRun?e.logger.log(`[dry-run] update ${w}`):await ve(w,`# Notification sound (disabled)
8
8
  export CODEX_DISABLE_SOUND=1
9
9
  export CODEX_CUSTOM_SOUND=""
10
- `,e);let l=u.join(e.homeDir,".codex","notify.sh");if(await v.pathExists(l)){let f=await v.readFile(l,"utf8"),k=f.replace(/^DEFAULT_CODEX_SOUND=.*$/m,'DEFAULT_CODEX_SOUND=""');e.options.dryRun?e.logger.log(`[dry-run] patch ${l} DEFAULT_CODEX_SOUND -> empty`):k!==f&&await v.writeFile(l,k,"utf8")}e.logger.ok("Notification sound disabled");return}let n;if(i&&!u.isAbsolute(i)?n=u.join(t,i):i?n=i:e.options.mode==="recommended"&&(n=u.join(t,"noti_1.wav")),!n||!await v.pathExists(n)){e.logger.warn("No notification sound selected or file missing; skipping sound setup");return}let r=u.isAbsolute(n),s=n.startsWith(u.join(e.rootDir,"sounds")),a=!r||s?u.join(o,u.basename(n)):n;(!r||s)&&(e.options.dryRun?e.logger.log(`[dry-run] cp ${n} ${a}`):await v.copy(n,a));let c=await ke(e),R=`# Notification sound
10
+ `,e);let l=u.join(e.homeDir,".codex","notify.sh");if(await v.pathExists(l)){let f=await v.readFile(l,"utf8"),k=f.replace(/^DEFAULT_CODEX_SOUND=.*$/m,'DEFAULT_CODEX_SOUND=""');e.options.dryRun?e.logger.log(`[dry-run] patch ${l} DEFAULT_CODEX_SOUND -> empty`):k!==f&&await v.writeFile(l,k,"utf8")}e.logger.ok("Notification sound disabled");return}let i;if(n&&!u.isAbsolute(n)?i=u.join(t,n):n?i=n:e.options.mode==="recommended"&&(i=u.join(t,"noti_1.wav")),!i||!await v.pathExists(i)){e.logger.warn("No notification sound selected or file missing; skipping sound setup");return}let r=u.isAbsolute(i),s=i.startsWith(u.join(e.rootDir,"sounds")),a=!r||s?u.join(o,u.basename(i)):i;(!r||s)&&(e.options.dryRun?e.logger.log(`[dry-run] cp ${i} ${a}`):await v.copy(i,a));let c=await ke(e),R=`# Notification sound
11
11
  export CODEX_DISABLE_SOUND=0
12
12
  export CODEX_CUSTOM_SOUND="${a}"
13
- `;e.options.dryRun?e.logger.log(`[dry-run] update ${c}`):await ve(c,R,e),e.logger.ok("Notification sound configured. Open a new shell or source your rc to apply.");let $=u.join(e.homeDir,".codex","notify.sh");if(await v.pathExists($)){let w=await v.readFile($,"utf8"),S=`DEFAULT_CODEX_SOUND="${a}"`,l=w.replace(/^DEFAULT_CODEX_SOUND=.*$/m,S);l!==w&&(e.options.dryRun?e.logger.log(`[dry-run] patch ${$} DEFAULT_CODEX_SOUND -> ${a}`):await v.writeFile($,l,"utf8"))}}async function ke(e){let t=e.options.shell||process.env.SHELL||"",o="auto";switch(o==="auto"&&(t.includes("zsh")?o="zsh":t.includes("fish")?o="fish":o="bash"),o){case"zsh":return u.join(e.homeDir,".zshrc");case"fish":return u.join(e.homeDir,".config","fish","config.fish");default:return u.join(e.homeDir,".bashrc")}}async function ve(e,t,o){let i="codex-1up";await v.ensureDir(u.dirname(e));let n="";if(await v.pathExists(e)){n=await v.readFile(e,"utf8");let s=`>>> ${i} >>>`,a=`<<< ${i} <<<`,c=new RegExp(`${s}[\\s\\S]*?${a}\\n?`,"g");n=n.replace(c,"")}let r=`>>> ${i} >>>
14
- ${t}<<< ${i} <<<
15
- `;await v.writeFile(e,n+r,"utf8")}import C from"fs-extra";import*as P from"path";async function Se(e){let t=P.join(e.homeDir,".codex","AGENTS.md"),o=e.options.globalAgents;if(o==="skip"){e.logger.info("Skipping global AGENTS.md creation");return}let i=P.join(e.rootDir,"templates","agent-templates","AGENTS-default.md");if(!await C.pathExists(i)){e.logger.warn(`Template not found at ${i}`);return}switch(o){case"create-default":if(await C.pathExists(t)){e.logger.info("Global AGENTS.md already exists; leaving unchanged");return}await C.ensureDir(P.dirname(t)),e.options.dryRun?e.logger.log(`[dry-run] cp ${i} ${t}`):await C.copy(i,t),e.logger.ok(`Wrote ${t}`);break;case"overwrite-default":if(await C.ensureDir(P.dirname(t)),await C.pathExists(t)){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await C.copy(t,r),e.logger.info(`Backed up existing AGENTS.md to: ${r}`)}e.options.dryRun?e.logger.log(`[dry-run] cp ${i} ${t}`):await C.copy(i,t),e.logger.ok(`Wrote ${t}`);break;case"append-default":if(await C.ensureDir(P.dirname(t)),await C.pathExists(t)){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await C.copy(t,r),e.logger.info(`Backed up existing AGENTS.md to: ${r}`)}let n=await C.readFile(i,"utf8");e.options.dryRun?e.logger.log(`[dry-run] append template to ${t}`):await C.appendFile(t,`
13
+ `;e.options.dryRun?e.logger.log(`[dry-run] update ${c}`):await ve(c,R,e),e.logger.ok("Notification sound configured. Open a new shell or source your rc to apply.");let $=u.join(e.homeDir,".codex","notify.sh");if(await v.pathExists($)){let w=await v.readFile($,"utf8"),S=`DEFAULT_CODEX_SOUND="${a}"`,l=w.replace(/^DEFAULT_CODEX_SOUND=.*$/m,S);l!==w&&(e.options.dryRun?e.logger.log(`[dry-run] patch ${$} DEFAULT_CODEX_SOUND -> ${a}`):await v.writeFile($,l,"utf8"))}}async function ke(e){let t=e.options.shell||process.env.SHELL||"",o="auto";switch(o==="auto"&&(t.includes("zsh")?o="zsh":t.includes("fish")?o="fish":o="bash"),o){case"zsh":return u.join(e.homeDir,".zshrc");case"fish":return u.join(e.homeDir,".config","fish","config.fish");default:return u.join(e.homeDir,".bashrc")}}async function ve(e,t,o){let n="codex-1up";await v.ensureDir(u.dirname(e));let i="";if(await v.pathExists(e)){i=await v.readFile(e,"utf8");let s=`>>> ${n} >>>`,a=`<<< ${n} <<<`,c=new RegExp(`${s}[\\s\\S]*?${a}\\n?`,"g");i=i.replace(c,"")}let r=`>>> ${n} >>>
14
+ ${t}<<< ${n} <<<
15
+ `;await v.writeFile(e,i+r,"utf8")}import C from"fs-extra";import*as P from"path";async function Se(e){let t=P.join(e.homeDir,".codex","AGENTS.md"),o=e.options.globalAgents;if(o==="skip"){e.logger.info("Skipping global AGENTS.md creation");return}let n=P.join(e.rootDir,"templates","agent-templates","AGENTS-default.md");if(!await C.pathExists(n)){e.logger.warn(`Template not found at ${n}`);return}switch(o){case"create-default":if(await C.pathExists(t)){e.logger.info("Global AGENTS.md already exists; leaving unchanged");return}await C.ensureDir(P.dirname(t)),e.options.dryRun?e.logger.log(`[dry-run] cp ${n} ${t}`):await C.copy(n,t),e.logger.ok(`Wrote ${t}`);break;case"overwrite-default":if(await C.ensureDir(P.dirname(t)),await C.pathExists(t)){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await C.copy(t,r),e.logger.info(`Backed up existing AGENTS.md to: ${r}`)}e.options.dryRun?e.logger.log(`[dry-run] cp ${n} ${t}`):await C.copy(n,t),e.logger.ok(`Wrote ${t}`);break;case"append-default":if(await C.ensureDir(P.dirname(t)),await C.pathExists(t)){let r=D(t);e.options.dryRun?e.logger.log(`[dry-run] cp ${t} ${r}`):await C.copy(t,r),e.logger.info(`Backed up existing AGENTS.md to: ${r}`)}let i=await C.readFile(n,"utf8");e.options.dryRun?e.logger.log(`[dry-run] append template to ${t}`):await C.appendFile(t,`
16
16
  ---
17
17
 
18
- ${n}`,"utf8"),e.logger.ok(`Appended template to ${t}`);break;default:e.options.skipConfirmation&&e.logger.info("Skipping global AGENTS.md creation (non-interactive mode)");break}}async function Re(e){if(e.options.noVscode)return;let t=e.options.vscodeId;if(!t){e.logger.info("VS Code extension id not provided. Use: --vscode <publisher.extension>");return}if(!await d("code")){e.logger.warn("'code' (VS Code) not in PATH; skipping extension install");return}if(e.options.dryRun){e.logger.log(`[dry-run] code --install-extension ${t}`);return}e.logger.info(`Installing VS Code extension: ${t}`),await m("code",["--install-extension",t,"--force"],{dryRun:!1,logger:e.logger}),e.logger.ok(`VS Code extension '${t}' installed (or already present)`)}import V from"fs-extra";import*as z from"path";async function Ee(e){let t=e.options.agentsMd;if(!t)return;let o=t;(await V.stat(o).catch(()=>null))?.isDirectory()&&(o=z.join(o,"AGENTS.md"));let i=z.join(e.rootDir,"templates","agent-templates","AGENTS-default.md");if(await V.pathExists(o)){e.logger.warn(`${o} already exists`);let n=D(o);e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${n}`):await V.copy(o,n),e.logger.info(`Backed up existing AGENTS.md to: ${n}`)}e.logger.info(`Writing starter AGENTS.md to: ${o}`),e.options.dryRun?e.logger.log(`[dry-run] write AGENTS.md to ${o}`):(await V.ensureDir(z.dirname(o)),await V.copy(i,o),e.logger.ok("Wrote AGENTS.md"))}var Ne="codex-1up";async function ae(e,t){let o=De.homedir(),i=re.join(o,`.${Ne}`);await rt.ensureDir(i);let n=new Date().toISOString().replace(/[:.]/g,"-").slice(0,-5),r=re.join(i,`install-${n}.log`),s=de(r);s.info(`==> ${Ne} installer`),s.info(`Log: ${r}`);let a={cwd:process.cwd(),homeDir:o,rootDir:t,logDir:i,logFile:r,options:e,logger:s};try{await me(a),await we(a),await he(a),await be(a),await $e(a),await Ce(a),await Se(a),await Re(a),await Ee(a),s.ok("All done. Open a new shell or 'source' your rc file to load aliases."),s.info("Next steps:"),s.info(" 1) codex # sign in; then ask it to plan a refactor"),s.info(" 2) ./bin/codex-1up agents --path $PWD # write a starter AGENTS.md to your repo"),s.info(" 3) Review ~/.codex/config.toml (see: https://github.com/openai/codex/blob/main/docs/config.md)")}catch(c){throw s.err(`Installation failed: ${c}`),c}}import{defineCommand as Q}from"citty";import{promises as H}from"fs";import{resolve as T,dirname as je}from"path";import{fileURLToPath as at}from"url";import{accessSync as Ie}from"fs";import st from"os";var Pe=je(at(import.meta.url));function lt(){let e=T(Pe,"../../"),t=T(Pe,"../../..");try{return Ie(T(e,"templates")),e}catch{}try{return Ie(T(t,"templates")),t}catch{}return t}var pt=lt();function se(){let e=T(st.homedir(),".codex"),t=T(e,"config.toml");return{CODEX_HOME:e,CFG:t}}async function le(e){return H.readFile(e,"utf8")}async function Te(e,t){await H.mkdir(je(e),{recursive:!0}),await H.writeFile(e,t,"utf8")}function Ae(e){let t=/^\[profiles\.(.+?)\]/gm,o=[],i;for(;i=t.exec(e);)o.push(i[1]);return o}function pe(e,t){let o=`profile = "${t}"`;if(/^profile\s*=\s*".*"/m.test(e))return e.replace(/^profile\s*=\s*".*"/m,o);let i=e.indexOf(`
19
- `);return i===-1?o+`
20
- `+e:e.slice(0,i+1)+o+`
21
- `+e.slice(i+1)}var Oe=Q({meta:{name:"config",description:"Manage Codex config profiles"},subCommands:{init:Q({meta:{name:"init",description:"Install unified config with multiple profiles"},args:{force:{type:"boolean",description:"Backup and overwrite if exists"}},async run({args:e}){let t=T(pt,"templates/codex-config.toml"),o=await le(t),{CFG:i}=se(),n=await H.access(i).then(()=>!0).catch(()=>!1);if(n&&!e.force){process.stdout.write(`${i} exists. Use --force to overwrite.
22
- `);return}if(n){let r=`${i}.backup.${Date.now()}`;await H.copyFile(i,r),process.stdout.write(`Backed up to ${r}
23
- `)}await Te(i,o),process.stdout.write(`Wrote ${i}
24
- `)}}),profiles:Q({meta:{name:"profiles",description:"List profiles in the current config"},async run(){let{CFG:e}=se(),t=await le(e),o=Ae(t);process.stdout.write(o.length?o.join(`
18
+ ${i}`,"utf8"),e.logger.ok(`Appended template to ${t}`);break;default:e.options.skipConfirmation&&e.logger.info("Skipping global AGENTS.md creation (non-interactive mode)");break}}async function Re(e){if(e.options.noVscode)return;let t=e.options.vscodeId;if(!t){e.logger.info("VS Code extension id not provided. Use: --vscode <publisher.extension>");return}if(!await d("code")){e.logger.warn("'code' (VS Code) not in PATH; skipping extension install");return}if(e.options.dryRun){e.logger.log(`[dry-run] code --install-extension ${t}`);return}e.logger.info(`Installing VS Code extension: ${t}`),await m("code",["--install-extension",t,"--force"],{dryRun:!1,logger:e.logger}),e.logger.ok(`VS Code extension '${t}' installed (or already present)`)}import V from"fs-extra";import*as z from"path";async function Ee(e){let t=e.options.agentsMd;if(!t)return;let o=t;(await V.stat(o).catch(()=>null))?.isDirectory()&&(o=z.join(o,"AGENTS.md"));let n=z.join(e.rootDir,"templates","agent-templates","AGENTS-default.md");if(await V.pathExists(o)){e.logger.warn(`${o} already exists`);let i=D(o);e.options.dryRun?e.logger.log(`[dry-run] cp ${o} ${i}`):await V.copy(o,i),e.logger.info(`Backed up existing AGENTS.md to: ${i}`)}e.logger.info(`Writing starter AGENTS.md to: ${o}`),e.options.dryRun?e.logger.log(`[dry-run] write AGENTS.md to ${o}`):(await V.ensureDir(z.dirname(o)),await V.copy(n,o),e.logger.ok("Wrote AGENTS.md"))}var Ne="codex-1up";async function ae(e,t){let o=De.homedir(),n=re.join(o,`.${Ne}`);await tt.ensureDir(n);let i=new Date().toISOString().replace(/[:.]/g,"-").slice(0,-5),r=re.join(n,`install-${i}.log`),s=de(r);s.info(`==> ${Ne} installer`),s.info(`Log: ${r}`);let a={cwd:process.cwd(),homeDir:o,rootDir:t,logDir:n,logFile:r,options:e,logger:s};try{await me(a),await we(a),await he(a),await be(a),await $e(a),await Ce(a),await Se(a),await Re(a),await Ee(a),s.ok("All done. Open a new shell or 'source' your rc file to load aliases."),s.info("Next steps:"),s.info(" 1) codex # sign in; then ask it to plan a refactor"),s.info(" 2) ./bin/codex-1up agents --path $PWD # write a starter AGENTS.md to your repo"),s.info(" 3) Review ~/.codex/config.toml (see: https://github.com/openai/codex/blob/main/docs/config.md)")}catch(c){throw s.err(`Installation failed: ${c}`),c}}import{defineCommand as K}from"citty";import{promises as H}from"fs";import{resolve as _,dirname as Ae}from"path";import{fileURLToPath as ot}from"url";import{accessSync as it}from"fs";import nt from"os";var Ie=Ae(ot(import.meta.url));function rt(){let e=Ie;for(let t=0;t<6;t++){try{return it(_(e,"templates","codex-config.toml")),e}catch{}e=_(e,"..")}return _(Ie,"..")}var at=rt();function se(){let e=_(nt.homedir(),".codex"),t=_(e,"config.toml");return{CODEX_HOME:e,CFG:t}}async function le(e){return H.readFile(e,"utf8")}async function Pe(e,t){await H.mkdir(Ae(e),{recursive:!0}),await H.writeFile(e,t,"utf8")}function Te(e){let t=/^\[profiles\.(.+?)\]/gm,o=[],n;for(;n=t.exec(e);)o.push(n[1]);return o}function pe(e,t){let o=`profile = "${t}"`;if(/^profile\s*=\s*".*"/m.test(e))return e.replace(/^profile\s*=\s*".*"/m,o);let n=e.indexOf(`
19
+ `);return n===-1?o+`
20
+ `+e:e.slice(0,n+1)+o+`
21
+ `+e.slice(n+1)}var je=K({meta:{name:"config",description:"Manage Codex config profiles"},subCommands:{init:K({meta:{name:"init",description:"Install unified config with multiple profiles"},args:{force:{type:"boolean",description:"Backup and overwrite if exists"}},async run({args:e}){let t=_(at,"templates/codex-config.toml"),o=await le(t),{CFG:n}=se(),i=await H.access(n).then(()=>!0).catch(()=>!1);if(i&&!e.force){process.stdout.write(`${n} exists. Use --force to overwrite.
22
+ `);return}if(i){let r=`${n}.backup.${Date.now()}`;await H.copyFile(n,r),process.stdout.write(`Backed up to ${r}
23
+ `)}await Pe(n,o),process.stdout.write(`Wrote ${n}
24
+ `)}}),profiles:K({meta:{name:"profiles",description:"List profiles in the current config"},async run(){let{CFG:e}=se(),t=await le(e),o=Te(t);process.stdout.write(o.length?o.join(`
25
25
  `)+`
26
26
  `:`No profiles found
27
- `)}}),"set-profile":Q({meta:{name:"set-profile",description:"Set the active profile in config.toml"},args:{name:{type:"positional",required:!0,description:"Profile name"}},async run({args:e}){let{CFG:t}=se(),o=await le(t),i=Ae(o),n=String(e.name);if(!i.includes(n))throw new Error(`Unknown profile: ${n}`);let r=pe(o,n);await Te(t,r),process.stdout.write(`profile set to ${n}
28
- `)}})}});var _e=dt(ct(import.meta.url));function ut(){let e=N(_e,"../../"),t=N(_e,"../../..");try{return Fe(N(e,"templates")),e}catch{}try{return Fe(N(t,"templates")),t}catch{}return t}var Z=ut(),Ue=ft({meta:{name:"install",description:"Run the codex-1up installer with validated flags"},args:{yes:{type:"boolean",description:"Non-interactive; accept safe defaults"},"dry-run":{type:"boolean",description:"Print actions without making changes"},"skip-confirmation":{type:"boolean",description:"Skip prompts"},shell:{type:"string",description:"auto|zsh|bash|fish"},vscode:{type:"string",description:"Install VS Code extension id"},"no-vscode":{type:"boolean",description:"Skip VS Code extension checks"},"git-external-diff":{type:"boolean",description:"Set difftastic as git external diff"},"install-node":{type:"string",description:"nvm|brew|skip"},"agents-md":{type:"string",description:"Write starter AGENTS.md to PATH (default PWD/AGENTS.md)",required:!1}},async run({args:e}){let t=N(L.homedir(),".codex","config.toml"),o=await fe(t),i=N(L.homedir(),".codex","notify.sh"),n=await fe(i),r=N(L.homedir(),".codex","AGENTS.md"),s=await fe(r),a,c=!o,R=process.stdout.isTTY&&!e["dry-run"]&&!e["skip-confirmation"]&&!e.yes,$="balanced",w,S,l;if(R){if(p.intro("codex-1up \xB7 Install"),o){let g=await p.confirm({message:"Overwrite existing ~/.codex/config.toml with the latest template? (backup will be created)",initialValue:!0});if(p.isCancel(g))return p.cancel("Install aborted");a=g?"yes":"no",c=g,g||p.log.info("Keeping existing config (no overwrite).")}{let ee=function(b){return[{label:"Skip (leave current setup)",value:"skip"},{label:"None (disable sounds)",value:"none"},...j.map(h=>({label:h,value:h})),{label:"Custom path\u2026",value:"custom"}]};var k=ee;let g=await p.select({message:"Active profile",options:[{label:"balanced (default)",value:"balanced"},{label:"safe",value:"safe"},{label:"minimal",value:"minimal"},{label:"yolo (risky)",value:"yolo"}],initialValue:"balanced"});if(p.isCancel(g))return p.cancel("Install aborted");$=g;let A=N(Z,"sounds"),j=[];try{j=(await U.readdir(A)).filter(b=>/\.(wav|mp3|ogg)$/i.test(b)).sort()}catch{}w="yes";let y=j.includes("noti_1.wav")?"noti_1.wav":j[0]||"none";async function te(b){let h=await p.text({message:"Enter absolute path to a .wav file",placeholder:b||"/absolute/path/to/sound.wav",validate(O){if(!O)return"Path required";if(!O.startsWith("/"))return"Use an absolute path";if(!/(\.wav|\.mp3|\.ogg)$/i.test(O))return"Supported: .wav, .mp3, .ogg"}});if(p.isCancel(h))return null;try{await U.access(String(h))}catch{return p.log.warn("File not found. Try again."),await te(String(h))}return String(h)}let M=await p.select({message:"Notification sound",options:ee(y),initialValue:y});if(p.isCancel(M))return p.cancel("Install aborted");if(M==="skip")w="no",l=void 0;else if(M==="custom"){let b=await te();if(b===null)return p.cancel("Install aborted");y=b}else y=M;if(M!=="skip"){for(;;){let b=await p.select({message:`Selected: ${y}. What next?`,options:[{label:"Preview \u25B6 (press p then Enter)",value:"preview"},{label:"Use this",value:"use"},{label:"Choose another\u2026",value:"change"}],initialValue:"use"});if(p.isCancel(b))return p.cancel("Install aborted");if(b==="use")break;if(b==="change"){let h=await p.select({message:"Notification sound",options:ee(y),initialValue:y});if(p.isCancel(h))return p.cancel("Install aborted");if(h==="custom"){let O=await te();if(O===null)return p.cancel("Install aborted");y=O}else if(h==="skip"){w="no",l=void 0;break}else y=h;continue}try{let h=y==="none"?"none":y.startsWith("/")?y:N(Z,"sounds",y);await gt(h)}catch(h){p.log.warn(String(h))}}l===void 0&&(l=y)}if(s){let b=await p.select({message:"Global ~/.codex/AGENTS.md",options:[{label:"Add to your existing AGENTS.md (Backup will be created)",value:"append-default"},{label:"Overwrite existing (Backup will be created)",value:"overwrite-default"},{label:"Skip \u2014 leave as-is",value:"skip"}],initialValue:"append-default"});if(p.isCancel(b))return p.cancel("Install aborted");S=b}else S="skip"}}let f={profile:$,overwriteConfig:a,notify:w,globalAgents:S,notificationSound:l,mode:"manual",installNode:e["install-node"]||"nvm",shell:String(e.shell||"auto"),vscodeId:e.vscode?String(e.vscode):void 0,noVscode:e["no-vscode"]||!1,agentsMd:typeof e["agents-md"]<"u"?String(e["agents-md"]||process.cwd()):void 0,dryRun:e["dry-run"]||!1,assumeYes:e.yes||!1,skipConfirmation:e["skip-confirmation"]||!1};if(R){let g=p.spinner();g.start("Installing prerequisites and writing config");try{await ae(f,Z),g.stop("Base install complete"),c?await mt($):p.log.info("Profile unchanged (existing config kept)."),p.outro("Install finished")}catch(A){throw g.stop("Installation failed"),p.cancel(`Installation failed: ${A}`),A}await Ge();return}try{R||(a=o?"no":a,c=!1,w=n?"no":"yes",S="skip",f.overwriteConfig=a,f.notify=w,f.globalAgents=S,f.notificationSound=l),await ae(f,Z),await Ge()}catch(g){throw p.cancel(`Installation failed: ${g}`),g}}});async function Ge(){let e=L.homedir(),t=N(e,".codex","config.toml"),o,i=[];try{let c=await U.readFile(t,"utf8"),R=Le.parse(c);o=R.profile;let $=R.profiles||{};i=Object.keys($)}catch{}let n=["codex","ast-grep","fd","rg","fzf","jq","yq","difft","difftastic"],s=(await Promise.all(n.map(async c=>{try{return await G(c),[c,!0]}catch{return[c,!1]}}))).filter(([,c])=>c).map(([c])=>c),a=[];a.push(""),a.push("codex-1up: Installation summary"),a.push("\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"),a.push(`Config: ${t}${o?` (active profile: ${o})`:""}`),i.length&&a.push(`Profiles: ${i.join(", ")}`),a.push(`Tools detected: ${s.join(", ")||"none"}`),a.push(""),a.push("Usage:"),a.push(" - Switch profile for a session: codex --profile <name>"),a.push(" - List available profiles: codex-1up config profiles"),a.push(" - Persist active profile: codex-1up config set-profile <name>"),a.push(" - Write AGENTS.md to a repo: codex-1up agents --path . --template default"),a.push(""),process.stdout.write(a.join(`
27
+ `)}}),"set-profile":K({meta:{name:"set-profile",description:"Set the active profile in config.toml"},args:{name:{type:"positional",required:!0,description:"Profile name"}},async run({args:e}){let{CFG:t}=se(),o=await le(t),n=Te(o),i=String(e.name);if(!n.includes(i))throw new Error(`Unknown profile: ${i}`);let r=pe(o,i);await Pe(t,r),process.stdout.write(`profile set to ${i}
28
+ `)}})}});var Oe=pt(lt(import.meta.url));function ct(){let e=Oe;for(let t=0;t<6;t++){try{return ft(N(e,"templates","codex-config.toml")),e}catch{}e=N(e,"..")}return N(Oe,"..")}var Y=ct(),Ge=st({meta:{name:"install",description:"Run the codex-1up installer with validated flags"},args:{yes:{type:"boolean",description:"Non-interactive; accept safe defaults"},"dry-run":{type:"boolean",description:"Print actions without making changes"},"skip-confirmation":{type:"boolean",description:"Skip prompts"},shell:{type:"string",description:"auto|zsh|bash|fish"},vscode:{type:"string",description:"Install VS Code extension id"},"no-vscode":{type:"boolean",description:"Skip VS Code extension checks"},"git-external-diff":{type:"boolean",description:"Set difftastic as git external diff"},"install-node":{type:"string",description:"nvm|brew|skip"},"agents-md":{type:"string",description:"Write starter AGENTS.md to PATH (default PWD/AGENTS.md)",required:!1}},async run({args:e}){let t=N(L.homedir(),".codex","config.toml"),o=await fe(t),n=N(L.homedir(),".codex","notify.sh"),i=await fe(n),r=N(L.homedir(),".codex","AGENTS.md"),s=await fe(r),a,c=!o,R=process.stdout.isTTY&&!e["dry-run"]&&!e["skip-confirmation"]&&!e.yes,$="balanced",w,S,l;if(R){if(p.intro("codex-1up \xB7 Install"),o){let g=await p.confirm({message:"Overwrite existing ~/.codex/config.toml with the latest template? (backup will be created)",initialValue:!0});if(p.isCancel(g))return p.cancel("Install aborted");a=g?"yes":"no",c=g,g||p.log.info("Keeping existing config (no overwrite).")}{let ee=function(b){return[{label:"Skip (leave current setup)",value:"skip"},{label:"None (disable sounds)",value:"none"},...A.map(h=>({label:h,value:h})),{label:"Custom path\u2026",value:"custom"}]};var k=ee;let g=await p.select({message:"Active profile",options:[{label:"balanced (default)",value:"balanced"},{label:"safe",value:"safe"},{label:"minimal",value:"minimal"},{label:"yolo (risky)",value:"yolo"}],initialValue:"balanced"});if(p.isCancel(g))return p.cancel("Install aborted");$=g;let T=N(Y,"sounds"),A=[];try{A=(await U.readdir(T)).filter(b=>/\.(wav|mp3|ogg)$/i.test(b)).sort()}catch{}w="yes";let y=A.includes("noti_1.wav")?"noti_1.wav":A[0]||"none";async function te(b){let h=await p.text({message:"Enter absolute path to a .wav file",placeholder:b||"/absolute/path/to/sound.wav",validate(j){if(!j)return"Path required";if(!j.startsWith("/"))return"Use an absolute path";if(!/(\.wav|\.mp3|\.ogg)$/i.test(j))return"Supported: .wav, .mp3, .ogg"}});if(p.isCancel(h))return null;try{await U.access(String(h))}catch{return p.log.warn("File not found. Try again."),await te(String(h))}return String(h)}let M=await p.select({message:"Notification sound",options:ee(y),initialValue:y});if(p.isCancel(M))return p.cancel("Install aborted");if(M==="skip")w="no",l=void 0;else if(M==="custom"){let b=await te();if(b===null)return p.cancel("Install aborted");y=b}else y=M;if(M!=="skip"){for(;;){let b=await p.select({message:`Selected: ${y}. What next?`,options:[{label:"Preview \u25B6 (press p then Enter)",value:"preview"},{label:"Use this",value:"use"},{label:"Choose another\u2026",value:"change"}],initialValue:"use"});if(p.isCancel(b))return p.cancel("Install aborted");if(b==="use")break;if(b==="change"){let h=await p.select({message:"Notification sound",options:ee(y),initialValue:y});if(p.isCancel(h))return p.cancel("Install aborted");if(h==="custom"){let j=await te();if(j===null)return p.cancel("Install aborted");y=j}else if(h==="skip"){w="no",l=void 0;break}else y=h;continue}try{let h=y==="none"?"none":y.startsWith("/")?y:N(Y,"sounds",y);await dt(h)}catch(h){p.log.warn(String(h))}}l===void 0&&(l=y)}if(s){let b=await p.select({message:"Global ~/.codex/AGENTS.md",options:[{label:"Add to your existing AGENTS.md (Backup will be created)",value:"append-default"},{label:"Overwrite existing (Backup will be created)",value:"overwrite-default"},{label:"Skip \u2014 leave as-is",value:"skip"}],initialValue:"append-default"});if(p.isCancel(b))return p.cancel("Install aborted");S=b}else S="skip"}}let f={profile:$,overwriteConfig:a,notify:w,globalAgents:S,notificationSound:l,mode:"manual",installNode:e["install-node"]||"nvm",shell:String(e.shell||"auto"),vscodeId:e.vscode?String(e.vscode):void 0,noVscode:e["no-vscode"]||!1,agentsMd:typeof e["agents-md"]<"u"?String(e["agents-md"]||process.cwd()):void 0,dryRun:e["dry-run"]||!1,assumeYes:e.yes||!1,skipConfirmation:e["skip-confirmation"]||!1};if(R){let g=p.spinner();g.start("Installing prerequisites and writing config");try{await ae(f,Y),g.stop("Base install complete"),c?await ut($):p.log.info("Profile unchanged (existing config kept)."),p.outro("Install finished")}catch(T){throw g.stop("Installation failed"),p.cancel(`Installation failed: ${T}`),T}await Fe();return}try{R||(a=o?"no":a,c=!1,w=i?"no":"yes",S="skip",f.overwriteConfig=a,f.notify=w,f.globalAgents=S,f.notificationSound=l),await ae(f,Y),await Fe()}catch(g){throw p.cancel(`Installation failed: ${g}`),g}}});async function Fe(){let e=L.homedir(),t=N(e,".codex","config.toml"),o,n=[];try{let c=await U.readFile(t,"utf8"),R=_e.parse(c);o=R.profile;let $=R.profiles||{};n=Object.keys($)}catch{}let i=["codex","ast-grep","fd","rg","fzf","jq","yq","difft","difftastic"],s=(await Promise.all(i.map(async c=>{try{return await G(c),[c,!0]}catch{return[c,!1]}}))).filter(([,c])=>c).map(([c])=>c),a=[];a.push(""),a.push("codex-1up: Installation summary"),a.push("\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"),a.push(`Config: ${t}${o?` (active profile: ${o})`:""}`),n.length&&a.push(`Profiles: ${n.join(", ")}`),a.push(`Tools detected: ${s.join(", ")||"none"}`),a.push(""),a.push("Usage:"),a.push(" - Switch profile for a session: codex --profile <name>"),a.push(" - List available profiles: codex-1up config profiles"),a.push(" - Persist active profile: codex-1up config set-profile <name>"),a.push(" - Write AGENTS.md to a repo: codex-1up agents --path . --template default"),a.push(""),process.stdout.write(a.join(`
29
29
  `)+`
30
- `)}async function gt(e){if(e.endsWith("/none")||e==="none")return;let t=[async o=>{await G("afplay"),await x`afplay ${o}`},async o=>{await G("paplay"),await x`paplay ${o}`},async o=>{await G("aplay"),await x`aplay ${o}`},async o=>{await G("mpg123"),await x`mpg123 -q ${o}`},async o=>{await G("ffplay"),await x`ffplay -nodisp -autoexit -loglevel quiet ${o}`}];for(let o of t)try{await o(e);return}catch{}throw new Error("No audio player found (afplay/paplay/aplay/mpg123/ffplay)")}async function mt(e){let t=N(L.homedir(),".codex","config.toml");try{let o=await U.readFile(t,"utf8"),i=pe(o,e);await U.writeFile(t,i,"utf8")}catch{}}async function fe(e){try{return await U.access(e),!0}catch{return!1}}import{defineCommand as wt}from"citty";import{promises as J}from"fs";import{accessSync as ht}from"fs";import{resolve as X,dirname as qe}from"path";import{fileURLToPath as yt}from"url";var Me=qe(yt(import.meta.url));function bt(){let e=X(Me,"../../"),t=X(Me,"../../..");try{return ht(X(e,"templates")),e}catch{}return t}var $t=bt();async function ce(e){try{return await J.access(e),!0}catch{return!1}}async function kt(e,t){if(await ce(t)){let i=`${t}.backup.${new Date().toISOString().replace(/[:.]/g,"").replace("T","_").slice(0,15)}`;await J.copyFile(t,i)}await J.mkdir(qe(t),{recursive:!0}),await J.copyFile(e,t)}var We=wt({meta:{name:"agents",description:"Write an AGENTS.md template"},args:{path:{type:"string",required:!0,description:"Target repo path or file"}},async run({args:e}){let t=String(e.path),o=X($t,"templates/agent-templates","AGENTS-default.md"),n=await ce(t).then(async r=>r&&(await J.stat(t)).isDirectory()).catch(()=>!1)?X(t,"AGENTS.md"):t;if(!await ce(o))throw new Error(`Template not found: ${o}`);await kt(o,n),process.stdout.write(`Wrote ${n}
31
- `)}});import{defineCommand as vt}from"citty";import{$ as Ct}from"zx";import{fileURLToPath as St}from"url";import{accessSync as Be}from"fs";import{dirname as Rt,resolve as K}from"path";var Ve=Rt(St(import.meta.url));function Et(){let e=K(Ve,"../../"),t=K(Ve,"../../..");try{return Be(K(e,"templates")),e}catch{}try{return Be(K(t,"templates")),t}catch{}return t}var Nt=Et(),ze=vt({meta:{name:"doctor",description:"Run environment checks"},async run(){await Ct`bash ${K(Nt,"scripts/doctor.sh")}`}});import{defineCommand as Dt}from"citty";import{$ as It}from"zx";import{fileURLToPath as Pt}from"url";import{accessSync as He}from"fs";import{dirname as Tt,resolve as Y}from"path";var xe=Tt(Pt(import.meta.url));function At(){let e=Y(xe,"../../"),t=Y(xe,"../../..");try{return He(Y(e,"templates")),e}catch{}try{return He(Y(t,"templates")),t}catch{}return t}var jt=At(),Je=Dt({meta:{name:"uninstall",description:"Clean up aliases and config created by this tool"},async run(){await It`bash ${Y(jt,"scripts/uninstall.sh")}`}});var Xe=Ot({meta:{name:"codex-1up",version:"0.1.0",description:"Power up Codex CLI with clean profiles config and helpers"},subCommands:{install:Ue,agents:We,doctor:ze,uninstall:Je,config:Oe}});Ft(Xe);
30
+ `)}async function dt(e){if(e.endsWith("/none")||e==="none")return;let t=[async o=>{await G("afplay"),await x`afplay ${o}`},async o=>{await G("paplay"),await x`paplay ${o}`},async o=>{await G("aplay"),await x`aplay ${o}`},async o=>{await G("mpg123"),await x`mpg123 -q ${o}`},async o=>{await G("ffplay"),await x`ffplay -nodisp -autoexit -loglevel quiet ${o}`}];for(let o of t)try{await o(e);return}catch{}throw new Error("No audio player found (afplay/paplay/aplay/mpg123/ffplay)")}async function ut(e){let t=N(L.homedir(),".codex","config.toml");try{let o=await U.readFile(t,"utf8"),n=pe(o,e);await U.writeFile(t,n,"utf8")}catch{}}async function fe(e){try{return await U.access(e),!0}catch{return!1}}import{defineCommand as gt}from"citty";import{promises as J}from"fs";import{accessSync as mt}from"fs";import{resolve as X,dirname as Ue}from"path";import{fileURLToPath as wt}from"url";var Le=Ue(wt(import.meta.url));function ht(){let e=Le;for(let t=0;t<6;t++){try{return mt(X(e,"templates","codex-config.toml")),e}catch{}e=X(e,"..")}return X(Le,"..")}var yt=ht();async function ce(e){try{return await J.access(e),!0}catch{return!1}}async function bt(e,t){if(await ce(t)){let n=`${t}.backup.${new Date().toISOString().replace(/[:.]/g,"").replace("T","_").slice(0,15)}`;await J.copyFile(t,n)}await J.mkdir(Ue(t),{recursive:!0}),await J.copyFile(e,t)}var Me=gt({meta:{name:"agents",description:"Write an AGENTS.md template"},args:{path:{type:"string",required:!0,description:"Target repo path or file"}},async run({args:e}){let t=String(e.path),o=X(yt,"templates/agent-templates","AGENTS-default.md"),i=await ce(t).then(async r=>r&&(await J.stat(t)).isDirectory()).catch(()=>!1)?X(t,"AGENTS.md"):t;if(!await ce(o))throw new Error(`Template not found: ${o}`);await bt(o,i),process.stdout.write(`Wrote ${i}
31
+ `)}});import{defineCommand as $t}from"citty";import{$ as kt}from"zx";import{fileURLToPath as vt}from"url";import{accessSync as Ct}from"fs";import{dirname as St,resolve as Q}from"path";var qe=St(vt(import.meta.url));function Rt(){let e=qe;for(let t=0;t<6;t++){try{return Ct(Q(e,"templates","codex-config.toml")),e}catch{}e=Q(e,"..")}return Q(qe,"..")}var Et=Rt(),We=$t({meta:{name:"doctor",description:"Run environment checks"},async run(){await kt`bash ${Q(Et,"scripts/doctor.sh")}`}});import{defineCommand as Nt}from"citty";import{$ as Dt}from"zx";import{fileURLToPath as It}from"url";import{accessSync as Pt}from"fs";import{dirname as Tt,resolve as Z}from"path";var Be=Tt(It(import.meta.url));function At(){let e=Be;for(let t=0;t<6;t++){try{return Pt(Z(e,"templates","codex-config.toml")),e}catch{}e=Z(e,"..")}return Z(Be,"..")}var jt=At(),Ve=Nt({meta:{name:"uninstall",description:"Clean up aliases and config created by this tool"},async run(){await Dt`bash ${Z(jt,"scripts/uninstall.sh")}`}});var ze=Ot({meta:{name:"codex-1up",version:"0.1.0",description:"Power up Codex CLI with clean profiles config and helpers"},subCommands:{install:Ge,agents:Me,doctor:We,uninstall:Ve,config:je}});Ft(ze);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "codex-1up",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "0.1.1",
5
+ "version": "0.1.3",
6
6
  "description": "TypeScript CLI for codex-1up (citty-based)",
7
7
  "bin": {
8
8
  "codex-1up": "bin/codex-1up.mjs"
@@ -29,6 +29,7 @@
29
29
  "scripts",
30
30
  "LICENSE",
31
31
  "templates",
32
+ "sounds",
32
33
  "bin",
33
34
  "README.md"
34
35
  ],
@@ -1,6 +1,7 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
+ import os from "node:os";
4
5
 
5
6
  interface PackageTarget {
6
7
  name: string;
@@ -122,6 +123,8 @@ async function publishPackages(
122
123
 
123
124
  const newVersion = bumpAllVersions(versionBump);
124
125
 
126
+ let repoSlug = "";
127
+
125
128
  for (const target of packageTargets.filter((pkg) => pkg.publish)) {
126
129
  const pkgPath = path.resolve(target.dir);
127
130
  const manifestPath = path.join(pkgPath, "package.json");
@@ -130,6 +133,13 @@ async function publishPackages(
130
133
  continue;
131
134
  }
132
135
  const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
136
+ try {
137
+ const repoUrl: string | undefined = manifest?.repository?.url;
138
+ if (repoUrl) {
139
+ const m = repoUrl.match(/github\.com\/(.+?)\.git$/);
140
+ if (m) repoSlug = m[1];
141
+ }
142
+ } catch {}
133
143
  if (manifest.private) {
134
144
  console.warn(
135
145
  `Skipping publish for ${target.name}; package.json is marked private`,
@@ -138,9 +148,10 @@ async function publishPackages(
138
148
  }
139
149
  // Install deps and build before publish
140
150
  // Copy assets from repo root into package (ephemeral for packing only)
141
- run("rm -rf templates scripts || true", pkgPath);
151
+ run("rm -rf templates scripts sounds || true", pkgPath);
142
152
  run("cp -R ../templates ./templates", pkgPath);
143
153
  run("cp -R ../scripts ./scripts", pkgPath);
154
+ run("cp -R ../sounds ./sounds", pkgPath);
144
155
 
145
156
  // Ensure README and LICENSE exist inside the package for npm UI
146
157
  try {
@@ -149,14 +160,6 @@ async function publishPackages(
149
160
  let readme = fs.readFileSync(rootReadme, "utf8");
150
161
  // If README uses local ./public images, rewrite to absolute GitHub raw URLs
151
162
  // Derive repo slug from package.json repository.url when possible
152
- let repoSlug = "";
153
- try {
154
- const repoUrl: string | undefined = manifest?.repository?.url;
155
- if (repoUrl) {
156
- const m = repoUrl.match(/github\.com\/(.+?)\.git$/);
157
- if (m) repoSlug = m[1];
158
- }
159
- } catch {}
160
163
  if (repoSlug) {
161
164
  readme = readme.replace(
162
165
  /\]\(\.\/public\//g,
@@ -180,15 +183,23 @@ async function publishPackages(
180
183
  run(`pnpm publish --no-git-checks${accessFlag}`, pkgPath);
181
184
 
182
185
  // Clean up ephemeral copies so repo doesn't keep duplicates
183
- try {
184
- fs.rmSync(path.join(pkgPath, "templates"), { recursive: true, force: true });
185
- fs.rmSync(path.join(pkgPath, "scripts"), { recursive: true, force: true });
186
- fs.rmSync(path.join(pkgPath, "README.md"), { force: true });
187
- fs.rmSync(path.join(pkgPath, "LICENSE"), { force: true });
188
- } catch {}
186
+ try {
187
+ fs.rmSync(path.join(pkgPath, "templates"), { recursive: true, force: true });
188
+ fs.rmSync(path.join(pkgPath, "scripts"), { recursive: true, force: true });
189
+ fs.rmSync(path.join(pkgPath, "sounds"), { recursive: true, force: true });
190
+ fs.rmSync(path.join(pkgPath, "README.md"), { force: true });
191
+ fs.rmSync(path.join(pkgPath, "LICENSE"), { force: true });
192
+ } catch {}
189
193
  }
190
194
 
191
195
  createGitCommitAndTag(newVersion);
196
+
197
+ // After tagging, create or update a GitHub Release with notes from CHANGELOG
198
+ try {
199
+ createGithubRelease(newVersion, repoSlug);
200
+ } catch (e) {
201
+ console.warn("Skipping GitHub Release creation:", e);
202
+ }
192
203
  }
193
204
 
194
205
  // Get version bump type from command line arguments
@@ -196,3 +207,59 @@ const args = process.argv.slice(2);
196
207
  const versionBumpArg = args[0] || "patch"; // Default to patch
197
208
 
198
209
  publishPackages(versionBumpArg).catch(console.error);
210
+
211
+ // -------------- helpers: GitHub Release --------------
212
+
213
+ function hasGhCLI(): boolean {
214
+ try {
215
+ execSync("gh --version", { stdio: "ignore" });
216
+ return true;
217
+ } catch {
218
+ return false;
219
+ }
220
+ }
221
+
222
+ function changelogSection(versionLike: string): string | null {
223
+ const file = path.resolve("CHANGELOG.md");
224
+ if (!fs.existsSync(file)) return null;
225
+ const text = fs.readFileSync(file, "utf8");
226
+ const re = new RegExp(
227
+ `^## \\\\[${versionLike.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\\\\]` + "[\\s\\S]*?(?=^## \\\\[(?:.|\\n)*?\\\\]|\n\n?$)",
228
+ "m",
229
+ );
230
+ const m = text.match(re);
231
+ return m ? m[0].trim() + "\n" : null;
232
+ }
233
+
234
+ function ghReleaseExists(tag: string): boolean {
235
+ try {
236
+ execSync(`gh release view ${tag}`, { stdio: "ignore" });
237
+ return true;
238
+ } catch {
239
+ return false;
240
+ }
241
+ }
242
+
243
+ function createGithubRelease(version: string, repoSlug: string) {
244
+ if (!hasGhCLI()) return;
245
+ const tag = `v${version}`;
246
+ const title = `codex-1up ${tag}`;
247
+ let notes = changelogSection(version);
248
+
249
+ // fallback: if no section for this semver (e.g., 0.1.1), try mapping to 0.4 if present
250
+ if (!notes) {
251
+ const alt = process.env.GH_NOTES_REF || "0.4";
252
+ notes = changelogSection(alt) || undefined;
253
+ }
254
+
255
+ const tmp = path.join(os.tmpdir(), `release-notes-${version}.md`);
256
+ if (notes) fs.writeFileSync(tmp, notes);
257
+
258
+ const exists = ghReleaseExists(tag);
259
+ const cmd = exists
260
+ ? `gh release edit ${tag} --title "${title}" ${notes ? `--notes-file ${tmp}` : "--generate-notes"}`
261
+ : `gh release create ${tag} --title "${title}" ${notes ? `--notes-file ${tmp}` : "--generate-notes"}`;
262
+
263
+ console.log(`${exists ? "Updating" : "Creating"} GitHub Release ${tag}...`);
264
+ execSync(cmd, { stdio: "inherit" });
265
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -3,7 +3,10 @@
3
3
  When you need to call tools from the shell, use this rubric:
4
4
 
5
5
  ## File Operations
6
- - Use `fd` for finding files: `fd --full-path '<pattern>' | head -n 1`
6
+ - Find files by file name: `fd`
7
+ - Find files with path name: `fd -p <file-path>`
8
+ - List files in a directory: `fd . <directory>`
9
+ - Find files with extension and pattern: `fd -e <extension> <pattern>`
7
10
 
8
11
  ## Structured Code Search
9
12
  - Find code structure: `ast-grep --lang <language> -p '<pattern>'`
@@ -18,6 +18,10 @@ network_access = true
18
18
  # Desktop notifications from the TUI: boolean or filtered list. Default: false
19
19
  # Examples: true | ["agent-turn-complete", "approval-requested"]
20
20
  notifications = false
21
+ # Show raw reasoning content when available (default: false)
22
+ show_raw_agent_reasoning = true
23
+ # Ensure we do not hide internal reasoning (default: false)
24
+ hide_agent_reasoning = false
21
25
 
22
26
  # Centralized feature flags — booleans only
23
27
  [features]