oh-my-agent 2.3.0 → 2.4.0

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.
Files changed (3) hide show
  1. package/README.md +5 -3
  2. package/bin/cli.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  The Ultimate Agent Orchestrator for agentic coding.
8
8
 
9
- Orchestrate 9 specialized domain agents (PM, Frontend, Backend, Mobile, QA, Debug, Brainstorm, DevWorkflow, Terraform) via **Serena Memory**. Features parallel CLI execution, real-time observability dashboards, and zero-config progressive skill loading. The batteries-included solution for agentic coding.
9
+ Orchestrate 10 specialized domain agents (PM, Frontend, Backend, DB, Mobile, QA, Debug, Brainstorm, DevWorkflow, Terraform) via **Serena Memory**. Features parallel CLI execution, real-time observability dashboards, and zero-config progressive skill loading. The batteries-included solution for agentic coding.
10
10
 
11
11
  ## Table of Contents
12
12
 
@@ -42,6 +42,7 @@ flowchart TD
42
42
  direction TB
43
43
  FE[frontend-agent]
44
44
  BE[backend-agent]
45
+ DB[db-agent]
45
46
  MB[mobile-agent]
46
47
  TF[tf-infra-agent]
47
48
  end
@@ -69,6 +70,7 @@ A collection of **Agent Skills** enabling collaborative multi-agent development.
69
70
  | **PM Agent** | Requirements analysis, task decomposition, architecture | "plan", "break down", "what should we build" |
70
71
  | **Frontend Agent** | React/Next.js, TypeScript, Tailwind CSS | "UI", "component", "styling" |
71
72
  | **Backend Agent** | FastAPI, PostgreSQL, JWT authentication | "API", "database", "authentication" |
73
+ | **DB Agent** | SQL/NoSQL modeling, normalization, integrity, backup, capacity | "ERD", "schema", "database design", "index tuning" |
72
74
  | **Mobile Agent** | Flutter cross-platform development | "mobile app", "iOS/Android" |
73
75
  | **QA Agent** | OWASP Top 10 security, performance, accessibility | "review security", "audit", "check performance" |
74
76
  | **Debug Agent** | Bug diagnosis, root cause analysis, regression tests | "bug", "error", "crash" |
@@ -102,9 +104,9 @@ Select your project type and skills will be installed to `.agents/skills/`, with
102
104
  | Preset | Skills |
103
105
  |--------|--------|
104
106
  | ✨ All | Everything |
105
- | 🌐 Fullstack | brainstorm, frontend, backend, pm, qa, debug, commit |
107
+ | 🌐 Fullstack | brainstorm, frontend, backend, db, pm, qa, debug, commit |
106
108
  | 🎨 Frontend | brainstorm, frontend, pm, qa, debug, commit |
107
- | ⚙️ Backend | brainstorm, backend, pm, qa, debug, commit |
109
+ | ⚙️ Backend | brainstorm, backend, db, pm, qa, debug, commit |
108
110
  | 📱 Mobile | brainstorm, mobile, pm, qa, debug, commit |
109
111
  | 🚀 DevOps | brainstorm, tf-infra, dev-workflow, pm, qa, debug, commit |
110
112
 
package/bin/cli.js CHANGED
@@ -319,7 +319,7 @@ ${J}`,initialValue:!0});if(D$(G)||!G)return{shouldCleanupBrain:!1,shouldCleanupI
319
319
  `).filter((R)=>R.trim()),B=!1;for(let R of Y){let[V,j]=R.split(":"),L=parseInt(V?.trim()||"",10);if(Number.isNaN(L))continue;if(G(L))B=!0,D(`Killing orphaned parallel agent PID=${L} (${j?.trim()||"unknown"})`),await q(L),J(S)}if(!B)D(`Removing stale PID list: ${S}`),J(S);else if(!$){await new Promise((R)=>setTimeout(R,1000));try{o5(S,{force:!0})}catch{}}}}catch{}else N(`No results directory found: ${I}`);if(z.shouldCleanupBrain||z.shouldCleanupImplicit||z.shouldCleanupKnowledge){let T=Z$(U,".gemini","antigravity");if(z.shouldCleanupBrain){let X=Z$(T,"brain");try{if(iu(X)){let S=iI(X);for(let P of S){let Y=Z$(X,P);D(`Removing brain file: ${Y}`),J(Y)}}}catch{}}if(z.shouldCleanupImplicit){let X=Z$(T,"implicit");try{if(iu(X)){let S=iI(X);for(let P of S){let Y=Z$(X,P);D(`Removing implicit file: ${Y}`),J(Y)}}}catch{}}if(z.shouldCleanupKnowledge){let X=Z$(T,"knowledge");try{if(iu(X)){let S=iI(X);for(let P of S){let Y=Z$(X,P);D(`Removing knowledge file: ${Y}`),J(Y)}}}catch{}}}if(u){console.log(JSON.stringify(v,null,2));return}if(console.clear(),H$(c$.default.bgMagenta(c$.default.white(" \uD83E\uDDF9 oh-my-agent cleanup "))),$)f(c$.default.yellow("Dry-run mode — no changes will be made"),"Mode");if(v.details.length>0){let T=[c$.default.bold("Cleanup Details"),...v.details.map((X)=>{if(X.startsWith("[DRY-RUN]"))return c$.default.yellow(X);if(X.startsWith("[CLEAN]"))return c$.default.green(X);return c$.default.cyan(X)})].join(`
320
320
  `);f(T,"Details")}let Q=[c$.default.bold("Summary"),"┌─────────┬────────┐",`│ ${c$.default.bold("Action")} │ ${c$.default.bold("Count")} │`,"├─────────┼────────┤",`│ Cleaned │ ${String(v.cleaned).padEnd(6)} │`,`│ Skipped │ ${String(v.skipped).padEnd(6)} │`,"└─────────┴────────┘"].join(`
321
321
  `);if(f(Q,"Results"),$)t(c$.default.yellow("Run without --dry-run to apply changes"));else t(c$.default.green("Cleanup complete!"))}import{execSync as EG}from"node:child_process";import{existsSync as CI,readdirSync as vQ,readFileSync as SW}from"node:fs";import{join as Ng}from"node:path";var x=T$(C$(),1);import{execSync as FG}from"node:child_process";import{execSync as t5}from"node:child_process";import{existsSync as nu,lstatSync as UW,mkdirSync as EI,readdirSync as _W,readlinkSync as vW,symlinkSync as zW,unlinkSync as DW,writeFileSync as nI}from"node:fs";import{dirname as a5,join as K$,relative as NW,resolve as wG}from"node:path";var y$="first-fluke/oh-my-agent",e5=`https://raw.githubusercontent.com/${y$}/main/.agents/skills`,GU=`https://raw.githubusercontent.com/${y$}/main/.agents`,Iu=".agents/skills";function JW(){try{return t5("gh --version",{stdio:"ignore"}),!0}catch{return!1}}async function GW($,u){try{return t5(`gh api repos/${y$}/contents/.agents/skills/${$}/${u} --jq '.[] | select(.type == "file") | .name'`,{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim().split(`
322
- `).filter(Boolean).map((I)=>`${u}/${I}`)}catch{return[]}}async function XW($,u){let g=`https://api.github.com/repos/${y$}/contents/.agents/skills/${$}/${u}`,U=await fetch(g);if(!U.ok)return[];return(await U.json()).filter((_)=>_.type==="file").map((_)=>`${u}/${_.name}`)}async function qW($,u){if(JW())return GW($,u);return XW($,u)}var D4={domain:[{name:"frontend-agent",desc:"React/Next.js UI specialist"},{name:"backend-agent",desc:"FastAPI/SQLAlchemy API specialist"},{name:"mobile-agent",desc:"Flutter/Dart mobile specialist"}],coordination:[{name:"brainstorm",desc:"Design-first ideation before planning"},{name:"pm-agent",desc:"Product manager - task decomposition"},{name:"qa-agent",desc:"QA - OWASP, Lighthouse, WCAG"},{name:"workflow-guide",desc:"Manual multi-agent orchestration"},{name:"orchestrator",desc:"Automated parallel CLI execution"}],utility:[{name:"debug-agent",desc:"Bug fixing specialist"},{name:"commit",desc:"Conventional Commits helper"}],infrastructure:[{name:"tf-infra-agent",desc:"Multi-cloud infrastructure with Terraform - AWS, GCP, Azure, OCI support"},{name:"dev-workflow",desc:"Monorepo developer workflows - mise tasks, git hooks, CI/CD, release automation"}]},s5={fullstack:["brainstorm","frontend-agent","backend-agent","pm-agent","qa-agent","debug-agent","commit","tf-infra-agent","dev-workflow"],frontend:["brainstorm","frontend-agent","pm-agent","qa-agent","debug-agent","commit"],backend:["brainstorm","backend-agent","pm-agent","qa-agent","debug-agent","commit","dev-workflow"],mobile:["brainstorm","mobile-agent","pm-agent","qa-agent","debug-agent","commit"],devops:["brainstorm","tf-infra-agent","dev-workflow","pm-agent","qa-agent","debug-agent","commit"],all:[...D4.domain,...D4.coordination,...D4.utility,...D4.infrastructure].map(($)=>$.name)},QW=["resources","config","scripts","templates"];async function TW($){let u=["SKILL.md"];for(let g of QW){let U=await qW($,g);u.push(...U)}return u}async function XU($,u){let g=K$(u,Iu,$),U=await TW($);for(let I of U){let _=`${e5}/${$}/${I}`,v=await fetch(_);if(!v.ok)continue;let z=await v.text(),D=K$(g,I),N=a5(D);if(!nu(N))EI(N,{recursive:!0});nI(D,z,"utf-8")}return!0}async function qU($){let u=K$($,Iu,"_shared"),g=["reasoning-templates.md","clarification-protocol.md","context-loading.md","skill-routing.md"];if(!nu(u))EI(u,{recursive:!0});for(let U of g){let I=`${e5}/_shared/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}async function $Q($){let u=K$($,".agents","workflows"),g=["brainstorm.md","coordinate.md","coordinate-pro.md","debug.md","orchestrate.md","plan.md","review.md","setup.md","tools.md"];if(!nu(u))EI(u,{recursive:!0});for(let U of g){let I=`${GU}/workflows/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}async function uQ($){let u=K$($,".agents","config"),g=K$($,".agents");if(!nu(u))EI(u,{recursive:!0});let U="user-preferences.yaml",I=`${GU}/config/${U}`,_=await fetch(I);if(_.ok){let N=await _.text();nI(K$(u,U),N,"utf-8")}let v="mcp.json",z=`${GU}/${v}`,D=await fetch(z);if(D.ok){let N=await D.text();nI(K$(g,v),N,"utf-8")}}function fI(){return[...D4.domain,...D4.coordination,...D4.utility,...D4.infrastructure]}var IQ={claude:".claude/skills",copilot:".github/skills"};function QU($,u,g){let U=[],I=[],_=wG($,Iu);for(let v of u){let z=IQ[v],D=K$($,z);if(!nu(D))EI(D,{recursive:!0});for(let N of g){let J=K$(_,N),G=K$(D,N);if(!nu(J)){I.push(`${z}/${N} (source missing)`);continue}try{if(UW(G).isSymbolicLink()){if(wG(a5(G),vW(G))===wG(J)){I.push(`${z}/${N} (already linked)`);continue}DW(G)}else{I.push(`${z}/${N} (real dir exists)`);continue}}catch(Q){}let q=NW(D,J);zW(q,G,"dir"),U.push(`${z}/${N}`)}}return{created:U,skipped:I}}async function gQ(){let $=process.env.HOME||process.env.USERPROFILE||"",u=K$($,".gemini","antigravity","global_workflows");if(!nu(u))EI(u,{recursive:!0});let g=["brainstorm.md","coordinate.md","coordinate-pro.md","debug.md","orchestrate.md","plan.md","review.md","setup.md","tools.md"];for(let U of g){let I=`${GU}/workflows/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}function UQ($){let u=K$($,Iu);if(!nu(u))return[];return _W(u,{withFileTypes:!0}).filter((g)=>g.isDirectory()&&!g.name.startsWith("_")).map((g)=>g.name)}function _Q($){let u=[];for(let[g,U]of Object.entries(IQ))if(nu(K$($,U)))u.push(g);return u}function iG(){try{return FG("gh --version",{stdio:"ignore"}),!0}catch{return!1}}function TU(){try{return FG("gh auth status",{stdio:"ignore"}),!0}catch{return!1}}function nG(){try{return FG(`gh api user/starred/${y$}`,{stdio:"ignore"}),!0}catch{return!1}}function SU(){return iG()&&TU()&&nG()}async function HU($,u,g){try{let U=EG(`${u} --version`,{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim();return{name:$,installed:!0,version:U,installCmd:g}}catch{return{name:$,installed:!1,installCmd:g}}}async function HW($){let u=process.env.HOME||process.env.USERPROFILE||"",U={gemini:{path:`${u}/.gemini/settings.json`,type:"json"},claude:{path:`${u}/.claude.json`,type:"json"},codex:{path:`${u}/.codex/config.toml`,type:"toml"}}[$];if(!U)return{configured:!1};if(CI(U.path))try{let I=SW(U.path,"utf-8");if(U.type==="json"){let _=JSON.parse(I);return{configured:!!(_.mcpServers||_.mcp),path:U.path}}return{configured:!0,path:U.path}}catch{return{configured:!1}}return{configured:!1}}async function PW(){let $=Ng(process.cwd(),Iu);if(!CI($))return[];let u=fI(),g=[];for(let U of u){let I=Ng($,U.name),_=Ng(I,"SKILL.md");g.push({name:U.name,installed:CI(I),hasSkillMd:CI(_)})}return g}async function YW(){let $=process.env.HOME||process.env.USERPROFILE||"",u=Ng($,".gemini","antigravity","global_workflows");if(!CI(u))return{installed:!1,count:0};try{return{installed:!0,count:vQ(u).filter((U)=>U.endsWith(".md")).length}}catch{return{installed:!1,count:0}}}async function zQ($=!1){let u=process.cwd(),g=await Promise.all([HU("gemini","gemini","bun install --global @google/gemini-cli"),HU("claude","claude","bun install --global @anthropic-ai/claude-code"),HU("codex","codex","bun install --global @openai/codex"),HU("qwen","qwen","bun install --global @qwen-code/qwen-code")]),U=await Promise.all(g.filter((T)=>T.installed).map(async(T)=>{let X=await HW(T.name);return{...T,mcp:X}})),I=await PW(),_=await YW(),v=!1;try{v=EG("git config --get rerere.enabled",{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim()==="true"}catch{}let z=Ng(u,".serena","memories"),D=CI(z),N=0;if(D)try{N=vQ(z).length}catch{}let J=g.filter((T)=>!T.installed),G=I.length>0?I.filter((T)=>!T.installed||!T.hasSkillMd):fI().map((T)=>({name:T.name,installed:!1,hasSkillMd:!1})),q=J.length+G.length+(_.installed?0:1)+(v?0:1);if($){let T={ok:q===0,issues:q,clis:g.map((X)=>({name:X.name,installed:X.installed,version:X.version||null})),mcp:U.map((X)=>({name:X.name,configured:X.mcp.configured,path:X.mcp.path||null})),skills:I.length>0?I.map((X)=>({name:X.name,installed:X.installed,complete:X.hasSkillMd})):[],missingSkills:G.map((X)=>X.name),globalWorkflows:{installed:_.installed,count:_.count},serena:{exists:D,fileCount:N},gitRerere:{enabled:v}};console.log(JSON.stringify(T,null,2)),process.exit(q===0?0:1)}console.clear(),H$(x.default.bgMagenta(x.default.white(" \uD83E\uDE7A oh-my-agent doctor ")));let Q=Mu();try{let T=[x.default.bold("\uD83D\uDD0D CLI Installation Status"),"┌─────────┬──────────┬─────────────┐",`│ ${x.default.bold("CLI")} │ ${x.default.bold("Status")} │ ${x.default.bold("Version")} │`,"├─────────┼──────────┼─────────────┤",...g.map((P)=>{let Y=P.installed?x.default.green("✅ Installed"):x.default.red("❌ Missing"),B=P.version||"-";return`│ ${P.name.padEnd(7)} │ ${Y.padEnd(8)} │ ${B.padEnd(11)} │`}),"└─────────┴──────────┴─────────────┘"].join(`
322
+ `).filter(Boolean).map((I)=>`${u}/${I}`)}catch{return[]}}async function XW($,u){let g=`https://api.github.com/repos/${y$}/contents/.agents/skills/${$}/${u}`,U=await fetch(g);if(!U.ok)return[];return(await U.json()).filter((_)=>_.type==="file").map((_)=>`${u}/${_.name}`)}async function qW($,u){if(JW())return GW($,u);return XW($,u)}var D4={domain:[{name:"frontend-agent",desc:"React/Next.js UI specialist"},{name:"backend-agent",desc:"FastAPI/SQLAlchemy API specialist"},{name:"db-agent",desc:"SQL/NoSQL data modeling, normalization, integrity, and capacity specialist"},{name:"mobile-agent",desc:"Flutter/Dart mobile specialist"}],coordination:[{name:"brainstorm",desc:"Design-first ideation before planning"},{name:"pm-agent",desc:"Product manager - task decomposition"},{name:"qa-agent",desc:"QA - OWASP, Lighthouse, WCAG"},{name:"workflow-guide",desc:"Manual multi-agent orchestration"},{name:"orchestrator",desc:"Automated parallel CLI execution"}],utility:[{name:"debug-agent",desc:"Bug fixing specialist"},{name:"commit",desc:"Conventional Commits helper"}],infrastructure:[{name:"tf-infra-agent",desc:"Multi-cloud infrastructure with Terraform - AWS, GCP, Azure, OCI support"},{name:"dev-workflow",desc:"Monorepo developer workflows - mise tasks, git hooks, CI/CD, release automation"}]},s5={fullstack:["brainstorm","frontend-agent","backend-agent","db-agent","pm-agent","qa-agent","debug-agent","commit","tf-infra-agent","dev-workflow"],frontend:["brainstorm","frontend-agent","pm-agent","qa-agent","debug-agent","commit"],backend:["brainstorm","backend-agent","db-agent","pm-agent","qa-agent","debug-agent","commit","dev-workflow"],mobile:["brainstorm","mobile-agent","pm-agent","qa-agent","debug-agent","commit"],devops:["brainstorm","tf-infra-agent","dev-workflow","pm-agent","qa-agent","debug-agent","commit"],all:[...D4.domain,...D4.coordination,...D4.utility,...D4.infrastructure].map(($)=>$.name)},QW=["resources","config","scripts","templates"];async function TW($){let u=["SKILL.md"];for(let g of QW){let U=await qW($,g);u.push(...U)}return u}async function XU($,u){let g=K$(u,Iu,$),U=await TW($);for(let I of U){let _=`${e5}/${$}/${I}`,v=await fetch(_);if(!v.ok)continue;let z=await v.text(),D=K$(g,I),N=a5(D);if(!nu(N))EI(N,{recursive:!0});nI(D,z,"utf-8")}return!0}async function qU($){let u=K$($,Iu,"_shared"),g=["reasoning-templates.md","clarification-protocol.md","context-loading.md","skill-routing.md"];if(!nu(u))EI(u,{recursive:!0});for(let U of g){let I=`${e5}/_shared/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}async function $Q($){let u=K$($,".agents","workflows"),g=["brainstorm.md","coordinate.md","coordinate-pro.md","debug.md","orchestrate.md","plan.md","review.md","setup.md","tools.md"];if(!nu(u))EI(u,{recursive:!0});for(let U of g){let I=`${GU}/workflows/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}async function uQ($){let u=K$($,".agents","config"),g=K$($,".agents");if(!nu(u))EI(u,{recursive:!0});let U="user-preferences.yaml",I=`${GU}/config/${U}`,_=await fetch(I);if(_.ok){let N=await _.text();nI(K$(u,U),N,"utf-8")}let v="mcp.json",z=`${GU}/${v}`,D=await fetch(z);if(D.ok){let N=await D.text();nI(K$(g,v),N,"utf-8")}}function fI(){return[...D4.domain,...D4.coordination,...D4.utility,...D4.infrastructure]}var IQ={claude:".claude/skills",copilot:".github/skills"};function QU($,u,g){let U=[],I=[],_=wG($,Iu);for(let v of u){let z=IQ[v],D=K$($,z);if(!nu(D))EI(D,{recursive:!0});for(let N of g){let J=K$(_,N),G=K$(D,N);if(!nu(J)){I.push(`${z}/${N} (source missing)`);continue}try{if(UW(G).isSymbolicLink()){if(wG(a5(G),vW(G))===wG(J)){I.push(`${z}/${N} (already linked)`);continue}DW(G)}else{I.push(`${z}/${N} (real dir exists)`);continue}}catch(Q){}let q=NW(D,J);zW(q,G,"dir"),U.push(`${z}/${N}`)}}return{created:U,skipped:I}}async function gQ(){let $=process.env.HOME||process.env.USERPROFILE||"",u=K$($,".gemini","antigravity","global_workflows");if(!nu(u))EI(u,{recursive:!0});let g=["brainstorm.md","coordinate.md","coordinate-pro.md","debug.md","orchestrate.md","plan.md","review.md","setup.md","tools.md"];for(let U of g){let I=`${GU}/workflows/${U}`,_=await fetch(I);if(!_.ok)continue;let v=await _.text();nI(K$(u,U),v,"utf-8")}}function UQ($){let u=K$($,Iu);if(!nu(u))return[];return _W(u,{withFileTypes:!0}).filter((g)=>g.isDirectory()&&!g.name.startsWith("_")).map((g)=>g.name)}function _Q($){let u=[];for(let[g,U]of Object.entries(IQ))if(nu(K$($,U)))u.push(g);return u}function iG(){try{return FG("gh --version",{stdio:"ignore"}),!0}catch{return!1}}function TU(){try{return FG("gh auth status",{stdio:"ignore"}),!0}catch{return!1}}function nG(){try{return FG(`gh api user/starred/${y$}`,{stdio:"ignore"}),!0}catch{return!1}}function SU(){return iG()&&TU()&&nG()}async function HU($,u,g){try{let U=EG(`${u} --version`,{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim();return{name:$,installed:!0,version:U,installCmd:g}}catch{return{name:$,installed:!1,installCmd:g}}}async function HW($){let u=process.env.HOME||process.env.USERPROFILE||"",U={gemini:{path:`${u}/.gemini/settings.json`,type:"json"},claude:{path:`${u}/.claude.json`,type:"json"},codex:{path:`${u}/.codex/config.toml`,type:"toml"}}[$];if(!U)return{configured:!1};if(CI(U.path))try{let I=SW(U.path,"utf-8");if(U.type==="json"){let _=JSON.parse(I);return{configured:!!(_.mcpServers||_.mcp),path:U.path}}return{configured:!0,path:U.path}}catch{return{configured:!1}}return{configured:!1}}async function PW(){let $=Ng(process.cwd(),Iu);if(!CI($))return[];let u=fI(),g=[];for(let U of u){let I=Ng($,U.name),_=Ng(I,"SKILL.md");g.push({name:U.name,installed:CI(I),hasSkillMd:CI(_)})}return g}async function YW(){let $=process.env.HOME||process.env.USERPROFILE||"",u=Ng($,".gemini","antigravity","global_workflows");if(!CI(u))return{installed:!1,count:0};try{return{installed:!0,count:vQ(u).filter((U)=>U.endsWith(".md")).length}}catch{return{installed:!1,count:0}}}async function zQ($=!1){let u=process.cwd(),g=await Promise.all([HU("gemini","gemini","bun install --global @google/gemini-cli"),HU("claude","claude","bun install --global @anthropic-ai/claude-code"),HU("codex","codex","bun install --global @openai/codex"),HU("qwen","qwen","bun install --global @qwen-code/qwen-code")]),U=await Promise.all(g.filter((T)=>T.installed).map(async(T)=>{let X=await HW(T.name);return{...T,mcp:X}})),I=await PW(),_=await YW(),v=!1;try{v=EG("git config --get rerere.enabled",{encoding:"utf-8",stdio:["pipe","pipe","ignore"]}).trim()==="true"}catch{}let z=Ng(u,".serena","memories"),D=CI(z),N=0;if(D)try{N=vQ(z).length}catch{}let J=g.filter((T)=>!T.installed),G=I.length>0?I.filter((T)=>!T.installed||!T.hasSkillMd):fI().map((T)=>({name:T.name,installed:!1,hasSkillMd:!1})),q=J.length+G.length+(_.installed?0:1)+(v?0:1);if($){let T={ok:q===0,issues:q,clis:g.map((X)=>({name:X.name,installed:X.installed,version:X.version||null})),mcp:U.map((X)=>({name:X.name,configured:X.mcp.configured,path:X.mcp.path||null})),skills:I.length>0?I.map((X)=>({name:X.name,installed:X.installed,complete:X.hasSkillMd})):[],missingSkills:G.map((X)=>X.name),globalWorkflows:{installed:_.installed,count:_.count},serena:{exists:D,fileCount:N},gitRerere:{enabled:v}};console.log(JSON.stringify(T,null,2)),process.exit(q===0?0:1)}console.clear(),H$(x.default.bgMagenta(x.default.white(" \uD83E\uDE7A oh-my-agent doctor ")));let Q=Mu();try{let T=[x.default.bold("\uD83D\uDD0D CLI Installation Status"),"┌─────────┬──────────┬─────────────┐",`│ ${x.default.bold("CLI")} │ ${x.default.bold("Status")} │ ${x.default.bold("Version")} │`,"├─────────┼──────────┼─────────────┤",...g.map((P)=>{let Y=P.installed?x.default.green("✅ Installed"):x.default.red("❌ Missing"),B=P.version||"-";return`│ ${P.name.padEnd(7)} │ ${Y.padEnd(8)} │ ${B.padEnd(11)} │`}),"└─────────┴──────────┴─────────────┘"].join(`
323
323
  `);if(f(T,"CLI Status"),J.length>0)f(J.map((P)=>`${x.default.yellow("→")} ${P.name}: ${x.default.dim(P.installCmd)}`).join(`
324
324
  `),"Install missing CLIs");if(U.length>0){let P=[x.default.bold("\uD83D\uDD17 MCP Connection Status"),"┌─────────┬──────────┬─────────────────────┐",`│ ${x.default.bold("CLI")} │ ${x.default.bold("MCP Config")} │ ${x.default.bold("Path")} │`,"├─────────┼──────────┼─────────────────────┤",...U.map((Y)=>{let B=Y.mcp.configured?x.default.green("✅ Configured"):x.default.yellow("⚠️ Not configured"),R=Y.mcp.path?Y.mcp.path.split("/").pop()||"":"-";return`│ ${Y.name.padEnd(7)} │ ${B.padEnd(8)} │ ${R.padEnd(19)} │`}),"└─────────┴──────────┴─────────────────────┘"].join(`
325
325
  `);f(P,"MCP Status")}let X=I.filter((P)=>P.installed).length,S=I.filter((P)=>P.hasSkillMd).length;if(I.length>0){let P=[x.default.bold(`\uD83D\uDCE6 Skills (${X}/${I.length} installed, ${S} complete)`),"┌────────────────────┬──────────┬─────────────┐",`│ ${x.default.bold("Skill")} │ ${x.default.bold("Installed")} │ ${x.default.bold("SKILL.md")} │`,"├────────────────────┼──────────┼─────────────┤",...I.map((Y)=>{let B=Y.installed?x.default.green("✅"):x.default.red("❌"),R=Y.hasSkillMd?x.default.green("✅"):x.default.red("❌");return`│ ${Y.name.padEnd(18)} │ ${B.padEnd(8)} │ ${R.padEnd(11)} │`}),"└────────────────────┴──────────┴─────────────┘"].join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-agent",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Professional agent skills for Google Antigravity IDE - PM, Frontend, Backend, Mobile, QA, and Debug specialists that work together seamlessly",
5
5
  "type": "module",
6
6
  "bin": {