@automagik/genie 3.260317.3 → 3.260317.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/genie.js
CHANGED
|
@@ -83,7 +83,7 @@ tmux set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
83
83
|
`,D.length-B>F&&Q>B)q+=D.slice(B,Q)+`
|
|
84
84
|
`+D.slice(Q+1);else q+=D.slice(B);return q.slice(1)}function wH(D){var F="",$=0,J;for(var B=0;B<D.length;$>=65536?B+=2:B++)if($=G3(D,B),J=DD[$],!J&&U3($)){if(F+=D[B],$>=65536)F+=D[B+1]}else F+=J||ZH($);return F}function fH(D,F,$){var J="",B=D.tag,X,Q,Y;for(X=0,Q=$.length;X<Q;X+=1){if(Y=$[X],D.replacer)Y=D.replacer.call($,String(X),Y);if(oD(D,F,Y,!1,!1)||typeof Y>"u"&&oD(D,F,null,!1,!1)){if(J!=="")J+=","+(!D.condenseFlow?" ":"");J+=D.dump}}D.tag=B,D.dump="["+J+"]"}function x4(D,F,$,J){var B="",X=D.tag,Q,Y,q;for(Q=0,Y=$.length;Q<Y;Q+=1){if(q=$[Q],D.replacer)q=D.replacer.call($,String(Q),q);if(oD(D,F+1,q,!0,!0,!1,!0)||typeof q>"u"&&oD(D,F+1,null,!0,!0,!1,!0)){if(!J||B!=="")B+=T1(D,F);if(D.dump&&V3===D.dump.charCodeAt(0))B+="-";else B+="- ";B+=D.dump}}D.tag=X,D.dump=B||"[]"}function uH(D,F,$){var J="",B=D.tag,X=Object.keys($),Q,Y,q,G,H;for(Q=0,Y=X.length;Q<Y;Q+=1){if(H="",J!=="")H+=", ";if(D.condenseFlow)H+='"';if(q=X[Q],G=$[q],D.replacer)G=D.replacer.call($,q,G);if(!oD(D,F,q,!1,!1))continue;if(D.dump.length>1024)H+="? ";if(H+=D.dump+(D.condenseFlow?'"':"")+":"+(D.condenseFlow?"":" "),!oD(D,F,G,!1,!1))continue;H+=D.dump,J+=H}D.tag=B,D.dump="{"+J+"}"}function xH(D,F,$,J){var B="",X=D.tag,Q=Object.keys($),Y,q,G,H,V,U;if(D.sortKeys===!0)Q.sort();else if(typeof D.sortKeys==="function")Q.sort(D.sortKeys);else if(D.sortKeys)throw new QD("sortKeys must be a boolean or a function");for(Y=0,q=Q.length;Y<q;Y+=1){if(U="",!J||B!=="")U+=T1(D,F);if(G=Q[Y],H=$[G],D.replacer)H=D.replacer.call($,G,H);if(!oD(D,F+1,G,!0,!0,!0))continue;if(V=D.tag!==null&&D.tag!=="?"||D.dump&&D.dump.length>1024,V)if(D.dump&&V3===D.dump.charCodeAt(0))U+="?";else U+="? ";if(U+=D.dump,V)U+=T1(D,F);if(!oD(D,F+1,H,!0,V))continue;if(D.dump&&V3===D.dump.charCodeAt(0))U+=":";else U+=": ";U+=D.dump,B+=U}D.tag=X,D.dump=B||"{}"}function y4(D,F,$){var J,B,X,Q,Y,q;B=$?D.explicitTypes:D.implicitTypes;for(X=0,Q=B.length;X<Q;X+=1)if(Y=B[X],(Y.instanceOf||Y.predicate)&&(!Y.instanceOf||typeof F==="object"&&F instanceof Y.instanceOf)&&(!Y.predicate||Y.predicate(F))){if($)if(Y.multi&&Y.representName)D.tag=Y.representName(F);else D.tag=Y.tag;else D.tag="?";if(Y.represent){if(q=D.styleMap[Y.tag]||Y.defaultStyle,DF.call(Y.represent)==="[object Function]")J=Y.represent(F,q);else if(FF.call(Y.represent,q))J=Y.represent[q](F,q);else throw new QD("!<"+Y.tag+'> tag resolver accepts not "'+q+'" style');D.dump=J}return!0}return!1}function oD(D,F,$,J,B,X,Q){if(D.tag=null,D.dump=$,!y4(D,$,!1))y4(D,$,!0);var Y=DF.call(D.dump),q=J,G;if(J)J=D.flowLevel<0||D.flowLevel>F;var H=Y==="[object Object]"||Y==="[object Array]",V,U;if(H)V=D.duplicates.indexOf($),U=V!==-1;if(D.tag!==null&&D.tag!=="?"||U||D.indent!==2&&F>0)B=!1;if(U&&D.usedDuplicates[V])D.dump="*ref_"+V;else{if(H&&U&&!D.usedDuplicates[V])D.usedDuplicates[V]=!0;if(Y==="[object Object]"){if(J&&Object.keys(D.dump).length!==0){if(xH(D,F,D.dump,B),U)D.dump="&ref_"+V+D.dump}else if(uH(D,F,D.dump),U)D.dump="&ref_"+V+" "+D.dump}else if(Y==="[object Array]"){if(J&&D.dump.length!==0){if(D.noArrayIndent&&!Q&&F>0)x4(D,F-1,D.dump,B);else x4(D,F,D.dump,B);if(U)D.dump="&ref_"+V+D.dump}else if(fH(D,F,D.dump),U)D.dump="&ref_"+V+" "+D.dump}else if(Y==="[object String]"){if(D.tag!=="?")PH(D,D.dump,F,X,q)}else if(Y==="[object Undefined]")return!1;else{if(D.skipInvalid)return!1;throw new QD("unacceptable kind of an object to dump "+Y)}if(D.tag!==null&&D.tag!=="?"){if(G=encodeURI(D.tag[0]==="!"?D.tag.slice(1):D.tag).replace(/!/g,"%21"),D.tag[0]==="!")G="!"+G;else if(G.slice(0,18)==="tag:yaml.org,2002:")G="!!"+G.slice(18);else G="!<"+G+">";D.dump=G+" "+D.dump}}return!0}function yH(D,F){var $=[],J=[],B,X;S1(D,$,J);for(B=0,X=J.length;B<X;B+=1)F.duplicates.push($[J[B]]);F.usedDuplicates=Array(X)}function S1(D,F,$){var J,B,X;if(D!==null&&typeof D==="object")if(B=F.indexOf(D),B!==-1){if($.indexOf(B)===-1)$.push(B)}else if(F.push(D),Array.isArray(D))for(B=0,X=D.length;B<X;B+=1)S1(D[B],F,$);else{J=Object.keys(D);for(B=0,X=J.length;B<X;B+=1)S1(D[J[B]],F,$)}}function hH(D,F){F=F||{};var $=new NH(F);if(!$.noRefs)yH(D,$);var J=D;if($.replacer)J=$.replacer.call({"":J},"",J);if(oD($,0,J,!0,!0))return $.dump+`
|
|
85
85
|
`;return""}function k1(D,F){return function(){throw Error("Function yaml."+D+" is removed in js-yaml 4. Use yaml."+F+" instead, which is now safe by default.")}}var Zq,Tq,Nq,Sq,Iq,bq,i,QD,Pq,kq,wq,e,yq,hq,gq,mq,lq,iq,sq,JG,BG,YG,HG,VG,WG,m4,l4,MG,AG,I1=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
|
|
86
|
-
\r`,_G,LG,ZG,SG,IG,PG,kG,uG,p4,q2,_8=1,d4=2,c4=3,L8=4,_1=1,xG=2,Z4=3,yG,hG,gG,i4,r4,o4,s4,Q2,S4,BH,XH,e4,DF,FF,P1=65279,QH=9,V3=10,YH=13,qH=32,GH=33,HH=34,Z1=35,VH=37,WH=38,UH=39,zH=42,$F=44,KH=45,T8=58,MH=61,EH=62,AH=63,RH=64,JF=91,BF=93,OH=96,XF=123,CH=124,QF=125,DD,jH,_H,TH=1,W3=2,qF=1,N1=2,GF=3,HF=4,Z0=5,gH,mH,VF,DR,FR,$R,JR,BR;var WF=S(()=>{/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */Zq=h4,Tq=Oq,Nq=Cq,Sq=_q,Iq=Lq,bq=jq,i={isNothing:Zq,isObject:Tq,toArray:Nq,repeat:Sq,isNegativeZero:Iq,extend:bq};H3.prototype=Object.create(Error.prototype);H3.prototype.constructor=H3;H3.prototype.toString=function(F){return this.name+": "+g4(this,F)};QD=H3;Pq=vq,kq=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],wq=["scalar","sequence","mapping"];e=uq;L1.prototype.extend=function(F){var $=[],J=[];if(F instanceof e)J.push(F);else if(Array.isArray(F))J=J.concat(F);else if(F&&(Array.isArray(F.implicit)||Array.isArray(F.explicit))){if(F.implicit)$=$.concat(F.implicit);if(F.explicit)J=J.concat(F.explicit)}else throw new QD("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");$.forEach(function(X){if(!(X instanceof e))throw new QD("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(X.loadKind&&X.loadKind!=="scalar")throw new QD("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(X.multi)throw new QD("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")}),J.forEach(function(X){if(!(X instanceof e))throw new QD("Specified list of YAML types (or a single Type object) contains a non-Type object.")});var B=Object.create(L1.prototype);return B.implicit=(this.implicit||[]).concat($),B.explicit=(this.explicit||[]).concat(J),B.compiledImplicit=L4(B,"implicit"),B.compiledExplicit=L4(B,"explicit"),B.compiledTypeMap=xq(B.compiledImplicit,B.compiledExplicit),B};yq=L1,hq=new e("tag:yaml.org,2002:str",{kind:"scalar",construct:function(D){return D!==null?D:""}}),gq=new e("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(D){return D!==null?D:[]}}),mq=new e("tag:yaml.org,2002:map",{kind:"mapping",construct:function(D){return D!==null?D:{}}}),lq=new yq({explicit:[hq,gq,mq]});iq=new e("tag:yaml.org,2002:null",{kind:"scalar",resolve:pq,construct:dq,predicate:cq,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"},empty:function(){return""}},defaultStyle:"lowercase"});sq=new e("tag:yaml.org,2002:bool",{kind:"scalar",resolve:rq,construct:nq,predicate:oq,represent:{lowercase:function(D){return D?"true":"false"},uppercase:function(D){return D?"TRUE":"FALSE"},camelcase:function(D){return D?"True":"False"}},defaultStyle:"lowercase"});JG=new e("tag:yaml.org,2002:int",{kind:"scalar",resolve:DG,construct:FG,predicate:$G,represent:{binary:function(D){return D>=0?"0b"+D.toString(2):"-0b"+D.toString(2).slice(1)},octal:function(D){return D>=0?"0o"+D.toString(8):"-0o"+D.toString(8).slice(1)},decimal:function(D){return D.toString(10)},hexadecimal:function(D){return D>=0?"0x"+D.toString(16).toUpperCase():"-0x"+D.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),BG=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");YG=/^[-+]?[0-9]+e/;HG=new e("tag:yaml.org,2002:float",{kind:"scalar",resolve:XG,construct:QG,predicate:GG,represent:qG,defaultStyle:"lowercase"}),VG=lq.extend({implicit:[iq,sq,JG,HG]}),WG=VG,m4=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),l4=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");MG=new e("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:UG,construct:zG,instanceOf:Date,represent:KG});AG=new e("tag:yaml.org,2002:merge",{kind:"scalar",resolve:EG});_G=new e("tag:yaml.org,2002:binary",{kind:"scalar",resolve:RG,construct:OG,predicate:jG,represent:CG}),LG=Object.prototype.hasOwnProperty,ZG=Object.prototype.toString;SG=new e("tag:yaml.org,2002:omap",{kind:"sequence",resolve:TG,construct:NG}),IG=Object.prototype.toString;PG=new e("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:bG,construct:vG}),kG=Object.prototype.hasOwnProperty;uG=new e("tag:yaml.org,2002:set",{kind:"mapping",resolve:wG,construct:fG}),p4=WG.extend({implicit:[MG,AG],explicit:[_G,SG,PG,uG]}),q2=Object.prototype.hasOwnProperty,yG=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,hG=/[\x85\u2028\u2029]/,gG=/[,\[\]\{\}]/,i4=/^(?:!|!!|![a-z\-]+!)$/i,r4=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;o4=Array(256),s4=Array(256);for(Q2=0;Q2<256;Q2++)o4[Q2]=N4(Q2)?1:0,s4[Q2]=N4(Q2);S4={YAML:function(F,$,J){var B,X,Q;if(F.version!==null)L(F,"duplication of %YAML directive");if(J.length!==1)L(F,"YAML directive accepts exactly one argument");if(B=/^([0-9]+)\.([0-9]+)$/.exec(J[0]),B===null)L(F,"ill-formed argument of the YAML directive");if(X=parseInt(B[1],10),Q=parseInt(B[2],10),X!==1)L(F,"unacceptable YAML version of the document");if(F.version=J[0],F.checkLineBreaks=Q<2,Q!==1&&Q!==2)Z8(F,"unsupported YAML version of the document")},TAG:function(F,$,J){var B,X;if(J.length!==2)L(F,"TAG directive accepts exactly two arguments");if(B=J[0],X=J[1],!i4.test(B))L(F,"ill-formed tag handle (first argument) of the TAG directive");if(q2.call(F.tagMap,B))L(F,'there is a previously declared suffix for "'+B+'" tag handle');if(!r4.test(X))L(F,"ill-formed tag prefix (second argument) of the TAG directive");try{X=decodeURIComponent(X)}catch(Q){L(F,"tag prefix is malformed: "+X)}F.tagMap[B]=X}};BH=$H,XH=JH,e4={loadAll:BH,load:XH},DF=Object.prototype.toString,FF=Object.prototype.hasOwnProperty,DD={};DD[0]="\\0";DD[7]="\\a";DD[8]="\\b";DD[9]="\\t";DD[10]="\\n";DD[11]="\\v";DD[12]="\\f";DD[13]="\\r";DD[27]="\\e";DD[34]="\\\"";DD[92]="\\\\";DD[133]="\\N";DD[160]="\\_";DD[8232]="\\L";DD[8233]="\\P";jH=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"],_H=/^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/;gH=hH,mH={dump:gH};VF=e4.load,DR=e4.loadAll,FR=mH.dump,$R=k1("safeLoad","load"),JR=k1("safeLoadAll","loadAll"),BR=k1("safeDump","dump")});import{existsSync as w1,readFileSync as pH,readdirSync as dH,realpathSync as cH}from"fs";import{dirname as I8,join as f1,resolve as b8}from"path";function iH(){let D=cH(process.argv[1]||""),F=[b8(I8(D),".."),b8(I8(D),"..",".."),b8(I8(import.meta.dir??__dirname),"..",".."),b8(I8(import.meta.dir??__dirname),"..")];for(let $ of F)if(w1(f1($,"plugins","genie","agents")))return $;return F[0]}function rH(D){let F=D.match(/^---\n([\s\S]*?)\n---/);if(!F)return{};try{return VF(F[1])??{}}catch{return{}}}function nH(D){if(!w1(D))return[];let F=[],$;try{$=dH(D,{withFileTypes:!0})}catch{return[]}for(let J of $){if(!J.isDirectory())continue;let B=f1(D,J.name,"AGENTS.md");if(!w1(B))continue;let X=pH(B,"utf-8"),Q=rH(X),Y=Q.name||J.name,q=Y.startsWith("council");F.push({name:Y,description:Q.description||"",agentPath:B,model:Q.model==="inherit"?void 0:Q.model,promptMode:Q.promptMode||void 0,category:q?"council":"role",color:Q.color})}return F}function sH(D){return v8.find((F)=>F.name===D)??null}function zF(D){return sH(D)?.agentPath??null}var __dirname="/home/runner/_work/genie/genie/src/lib",oH,u1,UF,z3,v8;var K3=S(()=>{WF();oH=f1(iH(),"plugins","genie","agents"),u1=nH(oH),UF=u1.filter((D)=>D.category==="role"),z3=u1.filter((D)=>D.category==="council"),v8=u1});var R3={};JD(R3,{rm:()=>p1,resolve:()=>E3,ls:()=>A3,loadIdentity:()=>c1,getProjectRoot:()=>EF,get:()=>$V,edit:()=>d1,add:()=>l1});import{execSync as x1}from"child_process";import{existsSync as M3}from"fs";import{mkdir as MF,readFile as aH,writeFile as tH}from"fs/promises";import{homedir as eH}from"os";import{dirname as y1,join as H2}from"path";function DV(){return process.env.GENIE_HOME??H2(eH(),".genie")}function h1(){return H2(DV(),"agent-directory.json")}function EF(){if(process.env.GENIE_PROJECT_ROOT)return process.env.GENIE_PROJECT_ROOT;try{return x1("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}function AF(){try{let D=x1("git rev-parse --git-common-dir",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),F=x1("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),{resolve:$}=P("path"),J=$(D),B=y1(J);if(B===F)return null;return B}catch{return null}}function g1(){return H2(EF(),".genie","agents.json")}function P8(D){return D?h1():g1()}async function G2(D){try{let F=await aH(D,"utf-8");return JSON.parse(F)}catch{return{entries:{},lastUpdated:new Date().toISOString()}}}async function FV(D,F){await MF(y1(F),{recursive:!0}),D.lastUpdated=new Date().toISOString(),await tH(F,JSON.stringify(D,null,2))}async function m1(D,F){await MF(y1(D),{recursive:!0});let $=await HD(D);try{let J=await G2(D),B=await F(J);return await FV(J,D),B}finally{await $()}}async function l1(D,F){if(!D.name||D.name.trim()==="")throw Error("Agent name is required.");if(!D.dir||D.dir.trim()==="")throw Error("Agent directory (--dir) is required.");if(!M3(D.dir))throw Error(`Directory does not exist: ${D.dir}`);let $=H2(D.dir,"AGENTS.md");if(!M3($))throw Error(`AGENTS.md not found in ${D.dir}. Each agent directory must contain an AGENTS.md file.`);let J={...D,promptMode:D.promptMode??"append",registeredAt:new Date().toISOString()},B=P8(F?.global);return await m1(B,(X)=>{if(X.entries[D.name])throw Error(`Agent "${D.name}" already exists. Use "genie dir edit" to update or "genie dir rm" first.`);X.entries[D.name]=J}),J}async function p1(D,F){let $=!1,J=P8(F?.global);return await m1(J,(B)=>{if(B.entries[D])delete B.entries[D],$=!0}),$}async function E3(D){let $=(await G2(g1())).entries[D];if($)return{entry:$,builtin:!1};let J=AF();if(J){let q=H2(J,".genie","agents.json"),H=(await G2(q)).entries[D];if(H)return{entry:H,builtin:!1}}let X=(await G2(h1())).entries[D];if(X)return{entry:X,builtin:!1};let Q=UF.find((q)=>q.name===D);if(Q)return{entry:KF(Q),builtin:!0};let Y=z3.find((q)=>q.name===D);if(Y)return{entry:KF(Y),builtin:!0};return null}async function A3(){let D=[],F=new Set,$=await G2(g1());for(let X of Object.values($.entries))D.push({...X,scope:"project"}),F.add(X.name);let J=AF();if(J){let X=H2(J,".genie","agents.json"),Q=await G2(X);for(let Y of Object.values(Q.entries))if(!F.has(Y.name))D.push({...Y,scope:"project"}),F.add(Y.name)}let B=await G2(h1());for(let X of Object.values(B.entries))if(!F.has(X.name))D.push({...X,scope:"global"}),F.add(X.name);return D}async function $V(D,F){let $=P8(F?.global);return(await G2($)).entries[D]??null}async function d1(D,F,$){let J=null,B=P8($?.global);if(await m1(B,(X)=>{let Q=X.entries[D];if(!Q)throw Error(`Agent "${D}" not found in directory.`);if(F.dir){if(!M3(F.dir))throw Error(`Directory does not exist: ${F.dir}`);let Y=H2(F.dir,"AGENTS.md");if(!M3(Y))throw Error(`AGENTS.md not found in ${F.dir}.`)}Object.assign(Q,F),J=Q}),!J)throw Error(`Agent "${D}" not found in directory.`);return J}function c1(D){let F=H2(D.dir,"AGENTS.md");if(M3(F))return F;return null}function KF(D){return{name:D.name,dir:"",promptMode:D.promptMode??"append",model:D.model,roles:[],registeredAt:"(built-in)"}}var O3=S(()=>{K3();w2()});function CF(D){return XV.has(D)}var C3,XV;var i1=S(()=>{C3=["PreToolUse","PostToolUse","SessionStart","SessionEnd","TeammateIdle","TaskCompleted"],XV=new Set(["PreToolUse","UserPromptSubmit","TeammateIdle","TaskCompleted","PermissionRequest"])});function k8(D,F="mosaic"){return`select-layout -t '${D}' ${F==="vertical"?"even-horizontal":"tiled"}`}function w8(D){if(D==="vertical")return"vertical";return"mosaic"}var _3={};JD(_3,{validateBranchName:()=>SF,setTeamStatus:()=>l8,pruneStaleWorktrees:()=>IF,listTeams:()=>g8,listMembers:()=>a1,killTeamMembers:()=>m8,hireAgent:()=>h8,getTeam:()=>AD,fireAgent:()=>o1,disbandTeam:()=>s1,createTeam:()=>n1});import{existsSync as f8}from"fs";import{mkdir as LF,readFile as u8,readdir as ZF,rm as zV,unlink as TF,writeFile as x8}from"fs/promises";import{homedir as KV}from"os";import j3,{join as aD}from"path";var{$:sD}=globalThis.Bun;function NF(){return process.env.GENIE_HOME??aD(KV(),".genie")}function y8(){return aD(NF(),"teams")}function MV(D){return D.replace(/\//g,"--")}function I0(D){let F=MV(j3.basename(D)===D?D:D);return aD(y8(),`${F}.json`)}function EV(D){let $=q0().terminal?.worktreeBase;if($){if(j3.isAbsolute($))return $;return aD(D,$)}let J=j3.basename(D);return aD(NF(),"worktrees",J)}function SF(D){let F=[];if(/\s/.test(D))F.push("contains spaces");if(D.includes(".."))F.push('contains ".."');if(D.includes("~"))F.push('contains "~"');if(D.includes("^"))F.push('contains "^"');if(D.includes(":"))F.push('contains ":"');if(D.includes("?"))F.push('contains "?"');if(D.includes("*"))F.push('contains "*"');if(D.includes("["))F.push('contains "["');if(D.includes("\\"))F.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(D))F.push("contains control characters");if(D.endsWith(".lock"))F.push('ends with ".lock"');if(D.endsWith("/"))F.push('ends with "/"');if(D.endsWith("."))F.push('ends with "."');if(D.startsWith("-"))F.push('starts with "-"');if(F.length>0)throw Error(`Invalid team name '${D}': must be a valid git branch name (${F.join(", ")})`)}async function r1(D){let $=(await p()).filter((J)=>J.role===D||J.id===D);for(let J of $){try{if(J.paneId&&J.paneId!=="inline"){let{execSync:B}=P("child_process");B(`tmux kill-pane -t ${J.paneId}`,{stdio:"ignore"})}}catch{}await wD(J.id)}}async function AV(D,F,$,J){try{await sD`git -C ${D} fetch origin ${J}`.quiet()}catch{}if(await LF(j3.dirname($),{recursive:!0}),f8($))return;let B=!1;try{await sD`git -C ${D} rev-parse --verify ${F}`.quiet(),B=!0}catch{}if(B){await sD`git -C ${D} worktree add ${$} ${F}`.quiet();return}try{await sD`git -C ${D} worktree add -b ${F} ${$} origin/${J}`.quiet()}catch{try{await sD`git -C ${D} worktree add -b ${F} ${$} ${J}`.quiet()}catch{await sD`git -C ${D} worktree add -b ${F} ${$}`.quiet()}}}async function n1(D,F,$="dev"){SF(D);let J=j3.resolve(F),B=y8();await LF(B,{recursive:!0});let X=I0(D);if(f8(X)){let H=await u8(X,"utf-8");return JSON.parse(H)}let Q=EV(J),Y=aD(Q,D);await AV(J,D,Y,$);let q=new Date().toISOString(),G={name:D,repo:J,baseBranch:$,worktreePath:Y,members:[],status:"in_progress",createdAt:q};if(z4()){G.nativeTeamsEnabled=!0;try{let H=await K4(D);G.nativeTeamParentSessionId=H.sessionId}catch{}}return await x8(X,JSON.stringify(G,null,2)),G}async function h8(D,F){let $=await AD(D);if(!$)throw Error(`Team "${D}" not found.`);let J;if(F==="council")J=z3.map((Q)=>Q.name).filter((Q)=>!$.members.includes(Q)),$.members.push(...J);else{if($.members.includes(F))return[];$.members.push(F),J=[F]}let B=I0(D);return await x8(B,JSON.stringify($,null,2)),J}async function o1(D,F){let $=await AD(D);if(!$)throw Error(`Team "${D}" not found.`);let J=$.members.indexOf(F);if(J===-1)return!1;$.members.splice(J,1);let B=I0(D);await x8(B,JSON.stringify($,null,2));try{await r1(F)}catch{}return!0}async function s1(D){let F=await AD(D);if(!F)return!1;if(F.nativeTeamsEnabled)try{await Q3(D)}catch{}for(let B of F.members)try{await r1(B)}catch{}let $=F.repo;if(F.worktreePath&&f8(F.worktreePath))try{await sD`git -C ${$} worktree remove ${F.worktreePath} --force`.quiet()}catch{try{await zV(F.worktreePath,{recursive:!0,force:!0}),await sD`git -C ${$} worktree prune`.quiet()}catch{}}let J=I0(D);try{await TF(J)}catch{return!1}return await IF($),!0}async function IF(D){let F=y8(),$;try{$=await ZF(F)}catch{return}for(let J of $){if(!J.endsWith(".json"))continue;try{let B=await u8(aD(F,J),"utf-8"),X=JSON.parse(B);if(X.worktreePath&&!f8(X.worktreePath))await TF(aD(F,J))}catch{}}try{await sD`git -C ${D} worktree prune`.quiet()}catch{}}async function AD(D){try{let F=await u8(I0(D),"utf-8");return JSON.parse(F)}catch{return null}}async function g8(){let D=y8();try{let F=await ZF(D),$=[];for(let J of F){if(!J.endsWith(".json"))continue;try{let B=await u8(aD(D,J),"utf-8");$.push(JSON.parse(B))}catch{}}return $}catch{return[]}}async function a1(D){let F=await AD(D);if(!F)return null;return F.members}async function m8(D){let F=await AD(D);if(!F)return;for(let $ of F.members)try{await r1($)}catch{}}async function l8(D,F){let $=I0(D),J=await HD($);try{let B=await AD(D);if(!B)throw Error(`Team "${D}" not found.`);B.status=F,await x8($,JSON.stringify(B,null,2))}finally{await J()}}var L3=S(()=>{KD();K3();m2();w2();lD()});var kF={};JD(kF,{isTeamHooked:()=>NV,injectTeamHooks:()=>TV});import{existsSync as bF}from"fs";import{mkdir as RV,readFile as vF,writeFile as OV}from"fs/promises";import{homedir as CV}from"os";import{join as t1}from"path";function _V(){return process.env.CLAUDE_CONFIG_DIR??t1(CV(),".claude")}function PF(D){let F=D.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase();return t1(_V(),"teams",F,"settings.json")}function LV(){let D={};for(let F of C3)D[F]=[{hooks:[{type:"command",command:p8,timeout:jV}]}];return D}async function ZV(D){let F={};if(bF(D))try{let Q=await vF(D,"utf-8");F=JSON.parse(Q)}catch{}let $=LV(),J=F.hooks;if(J){if(C3.every((Y)=>{return J[Y]?.some((G)=>G.hooks?.some((H)=>H.command===p8))}))return!1}let B=J?{...J}:{};for(let Q of C3){let Y=$[Q][0],q=B[Q]??[];if(!q.some((H)=>H.hooks?.some((V)=>V.command===p8)))B[Q]=[...q,Y]}F.hooks=B;let X=t1(D,"..");return await RV(X,{recursive:!0}),await OV(D,JSON.stringify(F,null,2)),!0}async function TV(D){let F=PF(D);return ZV(F)}async function NV(D){let F=PF(D);if(!bF(F))return!1;try{let $=await vF(F,"utf-8"),B=JSON.parse($).hooks;if(!B)return!1;return C3.every((X)=>{return B[X]?.some((Y)=>Y.hooks?.some((q)=>q.command===p8))})}catch{return!1}}var p8="genie hook dispatch",jV=15;var wF=S(()=>{i1()});var hF={};JD(hF,{suspendWorker:()=>yF,getIdleTimeoutMs:()=>xF,checkIdleWorkers:()=>IV,WATCHDOG_POLL_INTERVAL_MS:()=>SV});function xF(){let D=process.env.GENIE_IDLE_TIMEOUT_MS;if(D!==void 0){if(D==="")return fF;let F=Number(D);if(!Number.isNaN(F)&&F>=0)return F}return fF}async function yF(D,F=uF){let $=await F.registryGet(D);if(!$)return!1;if($.state==="suspended")return!0;if($.paneId&&$.paneId!=="inline")try{await F.executeTmux(`kill-pane -t '${$.paneId}'`)}catch{}return await F.registryUpdate(D,{state:"suspended",suspendedAt:new Date().toISOString()}),!0}async function IV(D=uF){let F=xF();if(F===0)return[];let $=await D.registryList(),J=[];for(let B of $){if(B.state!=="idle")continue;if(Date.now()-new Date(B.lastStateChange).getTime()<F)continue;if(!await D.isPaneAlive(B.paneId)){await D.registryUpdate(B.id,{state:"suspended",suspendedAt:new Date().toISOString()}),J.push(B.id);continue}if(await yF(B.id,D))J.push(B.id)}return J}var uF,fF=1800000,SV=60000;var gF=S(()=>{KD();FD();uF={registryGet:iD,registryList:p,registryUpdate:q1,executeTmux:f,isPaneAlive:TD}});var iF={};JD(iF,{handleWorkerStop:()=>D5,handleWorkerSpawn:()=>V2,handleWorkerKill:()=>e1,handleLsCommand:()=>F5});function mF(D){let{readFileSync:F,existsSync:$}=P("fs");if(!$(D))return!1;try{let J=Number.parseInt(F(D,"utf-8").trim());if(J>0)return process.kill(J,0),!0}catch{}return!1}async function bV(D){let{writeFileSync:F,mkdirSync:$}=P("fs"),{join:J}=P("path"),{homedir:B}=P("os"),X=J(B(),".genie","relay");$(X,{recursive:!0});let Q=J(X,"otel-relay.pid"),Y=J(X,"otel-relay.mjs");if(mF(Q))return!0;let q=J(process.env.CLAUDE_CONFIG_DIR??J(B(),".claude"),"teams",D,"inboxes"),G=X.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),H=q.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),V=Q.replace(/\\/g,"\\\\").replace(/'/g,"\\'");try{F(Y,`import { createServer } from 'http';
|
|
86
|
+
\r`,_G,LG,ZG,SG,IG,PG,kG,uG,p4,q2,_8=1,d4=2,c4=3,L8=4,_1=1,xG=2,Z4=3,yG,hG,gG,i4,r4,o4,s4,Q2,S4,BH,XH,e4,DF,FF,P1=65279,QH=9,V3=10,YH=13,qH=32,GH=33,HH=34,Z1=35,VH=37,WH=38,UH=39,zH=42,$F=44,KH=45,T8=58,MH=61,EH=62,AH=63,RH=64,JF=91,BF=93,OH=96,XF=123,CH=124,QF=125,DD,jH,_H,TH=1,W3=2,qF=1,N1=2,GF=3,HF=4,Z0=5,gH,mH,VF,DR,FR,$R,JR,BR;var WF=S(()=>{/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */Zq=h4,Tq=Oq,Nq=Cq,Sq=_q,Iq=Lq,bq=jq,i={isNothing:Zq,isObject:Tq,toArray:Nq,repeat:Sq,isNegativeZero:Iq,extend:bq};H3.prototype=Object.create(Error.prototype);H3.prototype.constructor=H3;H3.prototype.toString=function(F){return this.name+": "+g4(this,F)};QD=H3;Pq=vq,kq=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],wq=["scalar","sequence","mapping"];e=uq;L1.prototype.extend=function(F){var $=[],J=[];if(F instanceof e)J.push(F);else if(Array.isArray(F))J=J.concat(F);else if(F&&(Array.isArray(F.implicit)||Array.isArray(F.explicit))){if(F.implicit)$=$.concat(F.implicit);if(F.explicit)J=J.concat(F.explicit)}else throw new QD("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");$.forEach(function(X){if(!(X instanceof e))throw new QD("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(X.loadKind&&X.loadKind!=="scalar")throw new QD("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(X.multi)throw new QD("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")}),J.forEach(function(X){if(!(X instanceof e))throw new QD("Specified list of YAML types (or a single Type object) contains a non-Type object.")});var B=Object.create(L1.prototype);return B.implicit=(this.implicit||[]).concat($),B.explicit=(this.explicit||[]).concat(J),B.compiledImplicit=L4(B,"implicit"),B.compiledExplicit=L4(B,"explicit"),B.compiledTypeMap=xq(B.compiledImplicit,B.compiledExplicit),B};yq=L1,hq=new e("tag:yaml.org,2002:str",{kind:"scalar",construct:function(D){return D!==null?D:""}}),gq=new e("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(D){return D!==null?D:[]}}),mq=new e("tag:yaml.org,2002:map",{kind:"mapping",construct:function(D){return D!==null?D:{}}}),lq=new yq({explicit:[hq,gq,mq]});iq=new e("tag:yaml.org,2002:null",{kind:"scalar",resolve:pq,construct:dq,predicate:cq,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"},empty:function(){return""}},defaultStyle:"lowercase"});sq=new e("tag:yaml.org,2002:bool",{kind:"scalar",resolve:rq,construct:nq,predicate:oq,represent:{lowercase:function(D){return D?"true":"false"},uppercase:function(D){return D?"TRUE":"FALSE"},camelcase:function(D){return D?"True":"False"}},defaultStyle:"lowercase"});JG=new e("tag:yaml.org,2002:int",{kind:"scalar",resolve:DG,construct:FG,predicate:$G,represent:{binary:function(D){return D>=0?"0b"+D.toString(2):"-0b"+D.toString(2).slice(1)},octal:function(D){return D>=0?"0o"+D.toString(8):"-0o"+D.toString(8).slice(1)},decimal:function(D){return D.toString(10)},hexadecimal:function(D){return D>=0?"0x"+D.toString(16).toUpperCase():"-0x"+D.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),BG=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");YG=/^[-+]?[0-9]+e/;HG=new e("tag:yaml.org,2002:float",{kind:"scalar",resolve:XG,construct:QG,predicate:GG,represent:qG,defaultStyle:"lowercase"}),VG=lq.extend({implicit:[iq,sq,JG,HG]}),WG=VG,m4=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),l4=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");MG=new e("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:UG,construct:zG,instanceOf:Date,represent:KG});AG=new e("tag:yaml.org,2002:merge",{kind:"scalar",resolve:EG});_G=new e("tag:yaml.org,2002:binary",{kind:"scalar",resolve:RG,construct:OG,predicate:jG,represent:CG}),LG=Object.prototype.hasOwnProperty,ZG=Object.prototype.toString;SG=new e("tag:yaml.org,2002:omap",{kind:"sequence",resolve:TG,construct:NG}),IG=Object.prototype.toString;PG=new e("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:bG,construct:vG}),kG=Object.prototype.hasOwnProperty;uG=new e("tag:yaml.org,2002:set",{kind:"mapping",resolve:wG,construct:fG}),p4=WG.extend({implicit:[MG,AG],explicit:[_G,SG,PG,uG]}),q2=Object.prototype.hasOwnProperty,yG=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,hG=/[\x85\u2028\u2029]/,gG=/[,\[\]\{\}]/,i4=/^(?:!|!!|![a-z\-]+!)$/i,r4=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;o4=Array(256),s4=Array(256);for(Q2=0;Q2<256;Q2++)o4[Q2]=N4(Q2)?1:0,s4[Q2]=N4(Q2);S4={YAML:function(F,$,J){var B,X,Q;if(F.version!==null)L(F,"duplication of %YAML directive");if(J.length!==1)L(F,"YAML directive accepts exactly one argument");if(B=/^([0-9]+)\.([0-9]+)$/.exec(J[0]),B===null)L(F,"ill-formed argument of the YAML directive");if(X=parseInt(B[1],10),Q=parseInt(B[2],10),X!==1)L(F,"unacceptable YAML version of the document");if(F.version=J[0],F.checkLineBreaks=Q<2,Q!==1&&Q!==2)Z8(F,"unsupported YAML version of the document")},TAG:function(F,$,J){var B,X;if(J.length!==2)L(F,"TAG directive accepts exactly two arguments");if(B=J[0],X=J[1],!i4.test(B))L(F,"ill-formed tag handle (first argument) of the TAG directive");if(q2.call(F.tagMap,B))L(F,'there is a previously declared suffix for "'+B+'" tag handle');if(!r4.test(X))L(F,"ill-formed tag prefix (second argument) of the TAG directive");try{X=decodeURIComponent(X)}catch(Q){L(F,"tag prefix is malformed: "+X)}F.tagMap[B]=X}};BH=$H,XH=JH,e4={loadAll:BH,load:XH},DF=Object.prototype.toString,FF=Object.prototype.hasOwnProperty,DD={};DD[0]="\\0";DD[7]="\\a";DD[8]="\\b";DD[9]="\\t";DD[10]="\\n";DD[11]="\\v";DD[12]="\\f";DD[13]="\\r";DD[27]="\\e";DD[34]="\\\"";DD[92]="\\\\";DD[133]="\\N";DD[160]="\\_";DD[8232]="\\L";DD[8233]="\\P";jH=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"],_H=/^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/;gH=hH,mH={dump:gH};VF=e4.load,DR=e4.loadAll,FR=mH.dump,$R=k1("safeLoad","load"),JR=k1("safeLoadAll","loadAll"),BR=k1("safeDump","dump")});import{existsSync as w1,readFileSync as pH,readdirSync as dH,realpathSync as cH}from"fs";import{dirname as I8,join as f1,resolve as b8}from"path";function iH(){let D=cH(process.argv[1]||""),F=[b8(I8(D),".."),b8(I8(D),"..",".."),b8(I8(import.meta.dir??__dirname),"..",".."),b8(I8(import.meta.dir??__dirname),"..")];for(let $ of F)if(w1(f1($,"plugins","genie","agents")))return $;return F[0]}function rH(D){let F=D.match(/^---\n([\s\S]*?)\n---/);if(!F)return{};try{return VF(F[1])??{}}catch{return{}}}function nH(D){if(!w1(D))return[];let F=[],$;try{$=dH(D,{withFileTypes:!0})}catch{return[]}for(let J of $){if(!J.isDirectory())continue;let B=f1(D,J.name,"AGENTS.md");if(!w1(B))continue;let X=pH(B,"utf-8"),Q=rH(X),Y=Q.name||J.name,q=Y.startsWith("council");F.push({name:Y,description:Q.description||"",agentPath:B,model:Q.model==="inherit"?void 0:Q.model,promptMode:Q.promptMode||void 0,category:q?"council":"role",color:Q.color})}return F}function sH(D){return v8.find((F)=>F.name===D)??null}function zF(D){return sH(D)?.agentPath??null}var __dirname="/home/runner/_work/genie/genie/src/lib",oH,u1,UF,z3,v8;var K3=S(()=>{WF();oH=f1(iH(),"plugins","genie","agents"),u1=nH(oH),UF=u1.filter((D)=>D.category==="role"),z3=u1.filter((D)=>D.category==="council"),v8=u1});var R3={};JD(R3,{rm:()=>p1,resolve:()=>E3,ls:()=>A3,loadIdentity:()=>c1,getProjectRoot:()=>EF,get:()=>$V,edit:()=>d1,add:()=>l1});import{execSync as x1}from"child_process";import{existsSync as M3}from"fs";import{mkdir as MF,readFile as aH,writeFile as tH}from"fs/promises";import{homedir as eH}from"os";import{dirname as y1,join as H2}from"path";function DV(){return process.env.GENIE_HOME??H2(eH(),".genie")}function h1(){return H2(DV(),"agent-directory.json")}function EF(){if(process.env.GENIE_PROJECT_ROOT)return process.env.GENIE_PROJECT_ROOT;try{return x1("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return process.cwd()}}function AF(){try{let D=x1("git rev-parse --git-common-dir",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),F=x1("git rev-parse --show-toplevel",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim(),{resolve:$}=P("path"),J=$(D),B=y1(J);if(B===F)return null;return B}catch{return null}}function g1(){return H2(EF(),".genie","agents.json")}function P8(D){return D?h1():g1()}async function G2(D){try{let F=await aH(D,"utf-8");return JSON.parse(F)}catch{return{entries:{},lastUpdated:new Date().toISOString()}}}async function FV(D,F){await MF(y1(F),{recursive:!0}),D.lastUpdated=new Date().toISOString(),await tH(F,JSON.stringify(D,null,2))}async function m1(D,F){await MF(y1(D),{recursive:!0});let $=await HD(D);try{let J=await G2(D),B=await F(J);return await FV(J,D),B}finally{await $()}}async function l1(D,F){if(!D.name||D.name.trim()==="")throw Error("Agent name is required.");if(!D.dir||D.dir.trim()==="")throw Error("Agent directory (--dir) is required.");if(!M3(D.dir))throw Error(`Directory does not exist: ${D.dir}`);let $=H2(D.dir,"AGENTS.md");if(!M3($))throw Error(`AGENTS.md not found in ${D.dir}. Each agent directory must contain an AGENTS.md file.`);let J={...D,promptMode:D.promptMode??"append",registeredAt:new Date().toISOString()},B=P8(F?.global);return await m1(B,(X)=>{if(X.entries[D.name])throw Error(`Agent "${D.name}" already exists. Use "genie dir edit" to update or "genie dir rm" first.`);X.entries[D.name]=J}),J}async function p1(D,F){let $=!1,J=P8(F?.global);return await m1(J,(B)=>{if(B.entries[D])delete B.entries[D],$=!0}),$}async function E3(D){let $=(await G2(g1())).entries[D];if($)return{entry:$,builtin:!1};let J=AF();if(J){let q=H2(J,".genie","agents.json"),H=(await G2(q)).entries[D];if(H)return{entry:H,builtin:!1}}let X=(await G2(h1())).entries[D];if(X)return{entry:X,builtin:!1};let Q=UF.find((q)=>q.name===D);if(Q)return{entry:KF(Q),builtin:!0};let Y=z3.find((q)=>q.name===D);if(Y)return{entry:KF(Y),builtin:!0};return null}async function A3(){let D=[],F=new Set,$=await G2(g1());for(let X of Object.values($.entries))D.push({...X,scope:"project"}),F.add(X.name);let J=AF();if(J){let X=H2(J,".genie","agents.json"),Q=await G2(X);for(let Y of Object.values(Q.entries))if(!F.has(Y.name))D.push({...Y,scope:"project"}),F.add(Y.name)}let B=await G2(h1());for(let X of Object.values(B.entries))if(!F.has(X.name))D.push({...X,scope:"global"}),F.add(X.name);return D}async function $V(D,F){let $=P8(F?.global);return(await G2($)).entries[D]??null}async function d1(D,F,$){let J=null,B=P8($?.global);if(await m1(B,(X)=>{let Q=X.entries[D];if(!Q)throw Error(`Agent "${D}" not found in directory.`);if(F.dir){if(!M3(F.dir))throw Error(`Directory does not exist: ${F.dir}`);let Y=H2(F.dir,"AGENTS.md");if(!M3(Y))throw Error(`AGENTS.md not found in ${F.dir}.`)}Object.assign(Q,F),J=Q}),!J)throw Error(`Agent "${D}" not found in directory.`);return J}function c1(D){let F=H2(D.dir,"AGENTS.md");if(M3(F))return F;return null}function KF(D){return{name:D.name,dir:"",promptMode:D.promptMode??"append",model:D.model,roles:[],registeredAt:"(built-in)"}}var O3=S(()=>{K3();w2()});function CF(D){return XV.has(D)}var C3,XV;var i1=S(()=>{C3=["PreToolUse","PostToolUse","SessionStart","SessionEnd","TeammateIdle","TaskCompleted"],XV=new Set(["PreToolUse","UserPromptSubmit","TeammateIdle","TaskCompleted","PermissionRequest"])});function k8(D,F="mosaic"){return`select-layout -t '${D}' ${F==="vertical"?"even-horizontal":"tiled"}`}function w8(D){if(D==="vertical")return"vertical";return"mosaic"}var _3={};JD(_3,{validateBranchName:()=>SF,setTeamStatus:()=>l8,pruneStaleWorktrees:()=>IF,listTeams:()=>g8,listMembers:()=>a1,killTeamMembers:()=>m8,hireAgent:()=>h8,getTeam:()=>AD,fireAgent:()=>o1,disbandTeam:()=>s1,createTeam:()=>n1});import{existsSync as f8}from"fs";import{mkdir as LF,readFile as u8,readdir as ZF,rm as zV,unlink as TF,writeFile as x8}from"fs/promises";import{homedir as KV}from"os";import j3,{join as aD}from"path";var{$:sD}=globalThis.Bun;function NF(){return process.env.GENIE_HOME??aD(KV(),".genie")}function y8(){return aD(NF(),"teams")}function MV(D){return D.replace(/\//g,"--")}function I0(D){let F=MV(j3.basename(D)===D?D:D);return aD(y8(),`${F}.json`)}function EV(D){let $=q0().terminal?.worktreeBase;if($){if(j3.isAbsolute($))return $;return aD(D,$)}let J=j3.basename(D);return aD(NF(),"worktrees",J)}function SF(D){let F=[];if(/\s/.test(D))F.push("contains spaces");if(D.includes(".."))F.push('contains ".."');if(D.includes("~"))F.push('contains "~"');if(D.includes("^"))F.push('contains "^"');if(D.includes(":"))F.push('contains ":"');if(D.includes("?"))F.push('contains "?"');if(D.includes("*"))F.push('contains "*"');if(D.includes("["))F.push('contains "["');if(D.includes("\\"))F.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(D))F.push("contains control characters");if(D.endsWith(".lock"))F.push('ends with ".lock"');if(D.endsWith("/"))F.push('ends with "/"');if(D.endsWith("."))F.push('ends with "."');if(D.startsWith("-"))F.push('starts with "-"');if(F.length>0)throw Error(`Invalid team name '${D}': must be a valid git branch name (${F.join(", ")})`)}async function r1(D,F){let J=(await p()).filter((B)=>(B.role===D||B.id===D)&&(!F||B.team===F));for(let B of J){try{if(B.paneId&&B.paneId!=="inline"){let{execSync:X}=P("child_process");X(`tmux kill-pane -t ${B.paneId}`,{stdio:"ignore"})}}catch{}await wD(B.id)}}async function AV(D,F,$,J){try{await sD`git -C ${D} fetch origin ${J}`.quiet()}catch{}if(await LF(j3.dirname($),{recursive:!0}),f8($))return;let B=!1;try{await sD`git -C ${D} rev-parse --verify ${F}`.quiet(),B=!0}catch{}if(B){await sD`git -C ${D} worktree add ${$} ${F}`.quiet();return}try{await sD`git -C ${D} worktree add -b ${F} ${$} origin/${J}`.quiet()}catch{try{await sD`git -C ${D} worktree add -b ${F} ${$} ${J}`.quiet()}catch{await sD`git -C ${D} worktree add -b ${F} ${$}`.quiet()}}}async function n1(D,F,$="dev"){SF(D);let J=j3.resolve(F),B=y8();await LF(B,{recursive:!0});let X=I0(D);if(f8(X)){let H=await u8(X,"utf-8");return JSON.parse(H)}let Q=EV(J),Y=aD(Q,D);await AV(J,D,Y,$);let q=new Date().toISOString(),G={name:D,repo:J,baseBranch:$,worktreePath:Y,members:[],status:"in_progress",createdAt:q};if(z4()){G.nativeTeamsEnabled=!0;try{let H=await K4(D);G.nativeTeamParentSessionId=H.sessionId}catch{}}return await x8(X,JSON.stringify(G,null,2)),G}async function h8(D,F){let $=await AD(D);if(!$)throw Error(`Team "${D}" not found.`);let J;if(F==="council")J=z3.map((Q)=>Q.name).filter((Q)=>!$.members.includes(Q)),$.members.push(...J);else{if($.members.includes(F))return[];$.members.push(F),J=[F]}let B=I0(D);return await x8(B,JSON.stringify($,null,2)),J}async function o1(D,F){let $=await AD(D);if(!$)throw Error(`Team "${D}" not found.`);let J=$.members.indexOf(F);if(J===-1)return!1;$.members.splice(J,1);let B=I0(D);await x8(B,JSON.stringify($,null,2));try{await r1(F)}catch{}return!0}async function s1(D){let F=await AD(D);if(!F)return!1;if(F.nativeTeamsEnabled)try{await Q3(D)}catch{}for(let B of F.members)try{await r1(B,D)}catch{}let $=F.repo;if(F.worktreePath&&f8(F.worktreePath))try{await sD`git -C ${$} worktree remove ${F.worktreePath} --force`.quiet()}catch{try{await zV(F.worktreePath,{recursive:!0,force:!0}),await sD`git -C ${$} worktree prune`.quiet()}catch{}}let J=I0(D);try{await TF(J)}catch{return!1}return await IF($),!0}async function IF(D){let F=y8(),$;try{$=await ZF(F)}catch{return}for(let J of $){if(!J.endsWith(".json"))continue;try{let B=await u8(aD(F,J),"utf-8"),X=JSON.parse(B);if(X.worktreePath&&!f8(X.worktreePath))await TF(aD(F,J))}catch{}}try{await sD`git -C ${D} worktree prune`.quiet()}catch{}}async function AD(D){try{let F=await u8(I0(D),"utf-8");return JSON.parse(F)}catch{return null}}async function g8(){let D=y8();try{let F=await ZF(D),$=[];for(let J of F){if(!J.endsWith(".json"))continue;try{let B=await u8(aD(D,J),"utf-8");$.push(JSON.parse(B))}catch{}}return $}catch{return[]}}async function a1(D){let F=await AD(D);if(!F)return null;return F.members}async function m8(D){let F=await AD(D);if(!F)return;for(let $ of F.members)try{await r1($,D)}catch{}}async function l8(D,F){let $=I0(D),J=await HD($);try{let B=await AD(D);if(!B)throw Error(`Team "${D}" not found.`);B.status=F,await x8($,JSON.stringify(B,null,2))}finally{await J()}}var L3=S(()=>{KD();K3();m2();w2();lD()});var kF={};JD(kF,{isTeamHooked:()=>NV,injectTeamHooks:()=>TV});import{existsSync as bF}from"fs";import{mkdir as RV,readFile as vF,writeFile as OV}from"fs/promises";import{homedir as CV}from"os";import{join as t1}from"path";function _V(){return process.env.CLAUDE_CONFIG_DIR??t1(CV(),".claude")}function PF(D){let F=D.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase();return t1(_V(),"teams",F,"settings.json")}function LV(){let D={};for(let F of C3)D[F]=[{hooks:[{type:"command",command:p8,timeout:jV}]}];return D}async function ZV(D){let F={};if(bF(D))try{let Q=await vF(D,"utf-8");F=JSON.parse(Q)}catch{}let $=LV(),J=F.hooks;if(J){if(C3.every((Y)=>{return J[Y]?.some((G)=>G.hooks?.some((H)=>H.command===p8))}))return!1}let B=J?{...J}:{};for(let Q of C3){let Y=$[Q][0],q=B[Q]??[];if(!q.some((H)=>H.hooks?.some((V)=>V.command===p8)))B[Q]=[...q,Y]}F.hooks=B;let X=t1(D,"..");return await RV(X,{recursive:!0}),await OV(D,JSON.stringify(F,null,2)),!0}async function TV(D){let F=PF(D);return ZV(F)}async function NV(D){let F=PF(D);if(!bF(F))return!1;try{let $=await vF(F,"utf-8"),B=JSON.parse($).hooks;if(!B)return!1;return C3.every((X)=>{return B[X]?.some((Y)=>Y.hooks?.some((q)=>q.command===p8))})}catch{return!1}}var p8="genie hook dispatch",jV=15;var wF=S(()=>{i1()});var hF={};JD(hF,{suspendWorker:()=>yF,getIdleTimeoutMs:()=>xF,checkIdleWorkers:()=>IV,WATCHDOG_POLL_INTERVAL_MS:()=>SV});function xF(){let D=process.env.GENIE_IDLE_TIMEOUT_MS;if(D!==void 0){if(D==="")return fF;let F=Number(D);if(!Number.isNaN(F)&&F>=0)return F}return fF}async function yF(D,F=uF){let $=await F.registryGet(D);if(!$)return!1;if($.state==="suspended")return!0;if($.paneId&&$.paneId!=="inline")try{await F.executeTmux(`kill-pane -t '${$.paneId}'`)}catch{}return await F.registryUpdate(D,{state:"suspended",suspendedAt:new Date().toISOString()}),!0}async function IV(D=uF){let F=xF();if(F===0)return[];let $=await D.registryList(),J=[];for(let B of $){if(B.state!=="idle")continue;if(Date.now()-new Date(B.lastStateChange).getTime()<F)continue;if(!await D.isPaneAlive(B.paneId)){await D.registryUpdate(B.id,{state:"suspended",suspendedAt:new Date().toISOString()}),J.push(B.id);continue}if(await yF(B.id,D))J.push(B.id)}return J}var uF,fF=1800000,SV=60000;var gF=S(()=>{KD();FD();uF={registryGet:iD,registryList:p,registryUpdate:q1,executeTmux:f,isPaneAlive:TD}});var iF={};JD(iF,{handleWorkerStop:()=>D5,handleWorkerSpawn:()=>V2,handleWorkerKill:()=>e1,handleLsCommand:()=>F5});function mF(D){let{readFileSync:F,existsSync:$}=P("fs");if(!$(D))return!1;try{let J=Number.parseInt(F(D,"utf-8").trim());if(J>0)return process.kill(J,0),!0}catch{}return!1}async function bV(D){let{writeFileSync:F,mkdirSync:$}=P("fs"),{join:J}=P("path"),{homedir:B}=P("os"),X=J(B(),".genie","relay");$(X,{recursive:!0});let Q=J(X,"otel-relay.pid"),Y=J(X,"otel-relay.mjs");if(mF(Q))return!0;let q=J(process.env.CLAUDE_CONFIG_DIR??J(B(),".claude"),"teams",D,"inboxes"),G=X.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),H=q.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),V=Q.replace(/\\/g,"\\\\").replace(/'/g,"\\'");try{F(Y,`import { createServer } from 'http';
|
|
87
87
|
import { execSync } from 'child_process';
|
|
88
88
|
import { readFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
|
|
89
89
|
import { createHash } from 'crypto';
|
|
@@ -446,7 +446,7 @@ Wish: ${F.wish}`),console.log("\u2500".repeat(60));let $=Object.entries(F.groups
|
|
|
446
446
|
`)}function MW(){try{let D=Q$("git diff HEAD",{encoding:"utf-8",maxBuffer:1048576}),F=Q$("git diff --cached",{encoding:"utf-8",maxBuffer:1048576}),$=[D,F].filter(Boolean).join(`
|
|
447
447
|
`);if($.length>50000)return`${$.slice(0,50000)}
|
|
448
448
|
|
|
449
|
-
... (diff truncated at 50KB)`;return $}catch{return""}}function EW(D){let F=[],$=/^### Group (
|
|
449
|
+
... (diff truncated at 50KB)`;return $}catch{return""}}function EW(D){let F=[],$=/^### Group ([A-Za-z0-9]+):/gim,J=$.exec(D);while(J!==null){let B=J[1],X=J.index,Q=D.slice(X+J[0].length),Y=Q.search(/^### Group [A-Za-z0-9]+:/m),G=(Y!==-1?Q.slice(0,Y):Q).match(/\*\*depends-on:\*\*\s*(.+)/i),H=[];if(G){let V=G[1].trim();if(V.toLowerCase()!=="none")H=V.split(",").map((U)=>U.trim().replace(/^group\s*/i,"")).filter(Boolean)}F.push({name:B,dependsOn:H}),J=$.exec(D)}return F}async function AW(D,F){let $=b0(process.cwd(),".genie","brainstorms",F,"DRAFT.md");if(!i8($))console.error(`\u274C Draft not found: ${$}`),console.error(` Create it first: mkdir -p .genie/brainstorms/${F} && touch .genie/brainstorms/${F}/DRAFT.md`),process.exit(1);let J=await r8($,"utf-8"),B=o8({filePath:$,sectionContent:J,command:"brainstorm",skill:"brainstorm"}),X=await n8(B);console.log(`\uD83D\uDCDD Dispatching brainstorm to ${D} for "${F}"`),console.log(` Draft: ${$}`),await V2(D,{provider:"claude",team:process.env.GENIE_TEAM??"genie",extraArgs:["--append-system-prompt-file",X],initialPrompt:`Brainstorm "${F}". Your context is in the system prompt. Explore the idea, ask clarifying questions, and build toward a design.`})}async function RW(D,F){let $=b0(process.cwd(),".genie","brainstorms",F,"DESIGN.md");if(!i8($))console.error(`\u274C Design not found: ${$}`),console.error(` Run brainstorm first: genie brainstorm <agent> ${F}`),process.exit(1);let J=await r8($,"utf-8"),B=o8({filePath:$,sectionContent:J,command:"wish",skill:"wish"}),X=await n8(B);console.log(`\uD83D\uDCDD Dispatching wish to ${D} for "${F}"`),console.log(` Design: ${$}`),await V2(D,{provider:"claude",team:process.env.GENIE_TEAM??"genie",extraArgs:["--append-system-prompt-file",X],initialPrompt:`Create a wish from the design for "${F}". Your context is in the system prompt. Write the WISH.md with execution groups, acceptance criteria, and validation commands.`})}async function OW(D,F){let{slug:$,group:J}=S3(F),B=b0(process.cwd(),".genie","wishes",$,"WISH.md");if(!i8(B))console.error(`\u274C Wish not found: ${B}`),console.error(` Create it first: genie wish <agent> ${$}`),process.exit(1);let X=await r8(B,"utf-8"),Q=Y$(X,J);if(!Q){console.error(`\u274C Group "${J}" not found in ${B}`),console.error(" Available groups:");let V=X.match(/^### Group [A-Za-z0-9]+:.*$/gm);if(V)for(let U of V)console.error(` ${U}`);process.exit(1)}let Y=await T3($);if(!Y){let V=EW(X);Y=await D$($,V),console.log(`\uD83D\uDCDD Initialized state for wish "${$}" (${V.length} groups)`)}try{await F$($,J,D),console.log(`\u2705 Group "${J}" set to in_progress (assigned to ${D})`)}catch(V){let U=V instanceof Error?V.message:String(V);console.error(`\u274C ${U}`),process.exit(1)}let q=q$(X),G=o8({filePath:B,sectionContent:Q,wishContext:q,command:`work ${F}`,skill:"work"}),H=await n8(G);console.log(`\uD83D\uDD27 Dispatching work to ${D} for "${F}"`),console.log(` Wish: ${B}`),console.log(` Group: ${J}`),await V2(D,{provider:"claude",team:process.env.GENIE_TEAM??"genie",extraArgs:["--append-system-prompt-file",H],initialPrompt:`Execute Group ${J} of wish "${$}". Your full context is in the system prompt. Read the wish at ${B} if needed. Implement all deliverables, run validation, and report completion.`})}async function CW(D,F){let{slug:$,group:J}=S3(F),B=b0(process.cwd(),".genie","wishes",$,"WISH.md");if(!i8(B))console.error(`\u274C Wish not found: ${B}`),process.exit(1);let X=await r8(B,"utf-8"),Q=Y$(X,J);if(!Q)console.error(`\u274C Group "${J}" not found in ${B}`),process.exit(1);let Y=MW(),q=q$(X),G=[Q,"","## Git Diff (changes to review)","",Y?`\`\`\`diff
|
|
450
450
|
${Y}
|
|
451
451
|
\`\`\``:"(no uncommitted changes found \u2014 review committed changes)"].join(`
|
|
452
452
|
`),H=o8({filePath:B,sectionContent:G,wishContext:q,command:`review ${F}`,skill:"review"}),V=await n8(H);if(console.log(`\uD83D\uDD0D Dispatching review to ${D} for "${F}"`),console.log(` Wish: ${B}`),console.log(` Group: ${J}`),Y)console.log(` Diff: ${Y.split(`
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
### 🐛 Bug Fixes
|
|
4
|
+
- **core:** scope killWorkersByName by team — prevents killing other teams' workers ([`8dab7e7`](https://github.com/automagik-dev/genie/commit/8dab7e7d4f1bd3a65064508bb82db2917eab57f0))
|
|
5
|
+
- **dispatch:** accept lettered group names (A, B) not just numbered (1, 2) ([`f142f0c`](https://github.com/automagik-dev/genie/commit/f142f0c956284c1fae76a40dfcaa62d5c986a86f))
|
|
6
|
+
- **core:** team-lead prompt — skip status check before first dispatch ([`b6c6870`](https://github.com/automagik-dev/genie/commit/b6c687017a787b50e8587f66a935c9c85ec3f4ea))
|
|
7
|
+
|
|
8
|
+
### 👥 Contributors
|
|
9
|
+
- Test User
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automagik/genie",
|
|
3
|
-
"version": "3.260317.
|
|
3
|
+
"version": "3.260317.5",
|
|
4
4
|
"description": "Collaborative terminal toolkit for human + AI workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,7 +46,9 @@
|
|
|
46
46
|
"url": "git+https://github.com/automagik-dev/genie.git"
|
|
47
47
|
},
|
|
48
48
|
"openclaw": {
|
|
49
|
-
"extensions": [
|
|
49
|
+
"extensions": [
|
|
50
|
+
"./plugins/genie/index.ts"
|
|
51
|
+
]
|
|
50
52
|
},
|
|
51
53
|
"engines": {
|
|
52
54
|
"bun": ">=1.3.10"
|
|
@@ -54,5 +56,7 @@
|
|
|
54
56
|
"publishConfig": {
|
|
55
57
|
"access": "public"
|
|
56
58
|
},
|
|
57
|
-
"trustedDependencies": [
|
|
59
|
+
"trustedDependencies": [
|
|
60
|
+
"@biomejs/biome"
|
|
61
|
+
]
|
|
58
62
|
}
|
|
@@ -44,18 +44,18 @@ For cross-session agents, use `genie send '<text>' --to <agent>` via Bash.
|
|
|
44
44
|
<lifecycle>
|
|
45
45
|
|
|
46
46
|
## Phase 1 — Read Wish
|
|
47
|
-
Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria.
|
|
47
|
+
Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria.
|
|
48
48
|
|
|
49
|
-
**Gate:** All groups parsed, dependency DAG
|
|
49
|
+
**Gate:** All groups parsed, dependency DAG understood. If wish is unparseable or missing groups, report to PM and stop.
|
|
50
50
|
|
|
51
51
|
## Phase 2 — Execute Groups
|
|
52
|
-
Dispatch groups whose dependencies are satisfied.
|
|
52
|
+
Dispatch groups whose dependencies are satisfied. `genie work` auto-initializes state on first call — do NOT run `genie status` before your first dispatch. Just dispatch immediately.
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
genie work engineer <slug>#<group> #
|
|
55
|
+
genie work engineer <slug>#<group> # Auto-inits state, sets in_progress, spawns engineer
|
|
56
56
|
genie read <team>-engineer # Monitor progress
|
|
57
57
|
genie done <slug>#<group> # Mark group complete
|
|
58
|
-
genie status <slug> # Check
|
|
58
|
+
genie status <slug> # Check progress (only AFTER first dispatch)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
One group per engineer dispatch. Wait for completion before marking done.
|
|
@@ -44,18 +44,18 @@ For cross-session agents, use `genie send '<text>' --to <agent>` via Bash.
|
|
|
44
44
|
<lifecycle>
|
|
45
45
|
|
|
46
46
|
## Phase 1 — Read Wish
|
|
47
|
-
Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria.
|
|
47
|
+
Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria.
|
|
48
48
|
|
|
49
|
-
**Gate:** All groups parsed, dependency DAG
|
|
49
|
+
**Gate:** All groups parsed, dependency DAG understood. If wish is unparseable or missing groups, report to PM and stop.
|
|
50
50
|
|
|
51
51
|
## Phase 2 — Execute Groups
|
|
52
|
-
Dispatch groups whose dependencies are satisfied.
|
|
52
|
+
Dispatch groups whose dependencies are satisfied. `genie work` auto-initializes state on first call — do NOT run `genie status` before your first dispatch. Just dispatch immediately.
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
genie work engineer <slug>#<group> #
|
|
55
|
+
genie work engineer <slug>#<group> # Auto-inits state, sets in_progress, spawns engineer
|
|
56
56
|
genie read <team>-engineer # Monitor progress
|
|
57
57
|
genie done <slug>#<group> # Mark group complete
|
|
58
|
-
genie status <slug> # Check
|
|
58
|
+
genie status <slug> # Check progress (only AFTER first dispatch)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
One group per engineer dispatch. Wait for completion before marking done.
|
package/src/lib/team-manager.ts
CHANGED
|
@@ -120,10 +120,12 @@ export function validateBranchName(name: string): void {
|
|
|
120
120
|
// Agent Kill Helper
|
|
121
121
|
// ============================================================================
|
|
122
122
|
|
|
123
|
-
/** Best-effort kill all running workers matching a given agent name
|
|
124
|
-
async function killWorkersByName(agentName: string): Promise<void> {
|
|
123
|
+
/** Best-effort kill all running workers matching a given agent name, scoped to a team. */
|
|
124
|
+
async function killWorkersByName(agentName: string, teamName?: string): Promise<void> {
|
|
125
125
|
const workers = await registry.list();
|
|
126
|
-
const matches = workers.filter(
|
|
126
|
+
const matches = workers.filter(
|
|
127
|
+
(w) => (w.role === agentName || w.id === agentName) && (!teamName || w.team === teamName),
|
|
128
|
+
);
|
|
127
129
|
for (const w of matches) {
|
|
128
130
|
try {
|
|
129
131
|
if (w.paneId && w.paneId !== 'inline') {
|
|
@@ -312,10 +314,10 @@ export async function disbandTeam(teamName: string): Promise<boolean> {
|
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
316
|
|
|
315
|
-
// Kill all running team members
|
|
317
|
+
// Kill all running team members (scoped to this team only)
|
|
316
318
|
for (const member of config.members) {
|
|
317
319
|
try {
|
|
318
|
-
await killWorkersByName(member);
|
|
320
|
+
await killWorkersByName(member, teamName);
|
|
319
321
|
} catch {
|
|
320
322
|
// Best-effort — continue with other members
|
|
321
323
|
}
|
|
@@ -426,14 +428,14 @@ export async function listMembers(teamName: string): Promise<string[] | null> {
|
|
|
426
428
|
return config.members;
|
|
427
429
|
}
|
|
428
430
|
|
|
429
|
-
/** Kill all running workers for a team's members.
|
|
431
|
+
/** Kill all running workers for a team's members. Scoped to the team — won't kill other teams' workers. */
|
|
430
432
|
export async function killTeamMembers(teamName: string): Promise<void> {
|
|
431
433
|
const config = await getTeam(teamName);
|
|
432
434
|
if (!config) return;
|
|
433
435
|
|
|
434
436
|
for (const member of config.members) {
|
|
435
437
|
try {
|
|
436
|
-
await killWorkersByName(member);
|
|
438
|
+
await killWorkersByName(member, teamName);
|
|
437
439
|
} catch {
|
|
438
440
|
// Best-effort — continue with other members
|
|
439
441
|
}
|
|
@@ -140,11 +140,12 @@ function getGitDiff(): string {
|
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* Parse WISH.md content to extract group definitions for state initialization.
|
|
143
|
-
* Looks for `### Group <
|
|
143
|
+
* Looks for `### Group <id>: <title>` headings and `**depends-on:**` lines.
|
|
144
|
+
* Accepts both numbered (Group 1) and lettered (Group A) identifiers.
|
|
144
145
|
*/
|
|
145
146
|
export function parseWishGroups(content: string): GroupDefinition[] {
|
|
146
147
|
const groups: GroupDefinition[] = [];
|
|
147
|
-
const groupPattern = /^### Group (
|
|
148
|
+
const groupPattern = /^### Group ([A-Za-z0-9]+):/gim;
|
|
148
149
|
|
|
149
150
|
let match: RegExpExecArray | null = groupPattern.exec(content);
|
|
150
151
|
while (match !== null) {
|
|
@@ -153,7 +154,7 @@ export function parseWishGroups(content: string): GroupDefinition[] {
|
|
|
153
154
|
|
|
154
155
|
// Find the next group heading or end of content
|
|
155
156
|
const rest = content.slice(start + match[0].length);
|
|
156
|
-
const nextGroupIdx = rest.search(/^### Group
|
|
157
|
+
const nextGroupIdx = rest.search(/^### Group [A-Za-z0-9]+:/m);
|
|
157
158
|
const section = nextGroupIdx !== -1 ? rest.slice(0, nextGroupIdx) : rest;
|
|
158
159
|
|
|
159
160
|
// Look for **depends-on:** line within this group section
|
|
@@ -274,7 +275,7 @@ export async function workDispatchCommand(agentName: string, ref: string): Promi
|
|
|
274
275
|
if (!groupSection) {
|
|
275
276
|
console.error(`❌ Group "${group}" not found in ${wishPath}`);
|
|
276
277
|
console.error(' Available groups:');
|
|
277
|
-
const groups = content.match(/^### Group
|
|
278
|
+
const groups = content.match(/^### Group [A-Za-z0-9]+:.*$/gm);
|
|
278
279
|
if (groups) {
|
|
279
280
|
for (const g of groups) console.error(` ${g}`);
|
|
280
281
|
}
|