@automagik/genie 4.260325.3 → 4.260325.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.
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "genie",
13
- "version": "4.260325.3",
13
+ "version": "4.260325.5",
14
14
  "source": "./plugins/genie",
15
15
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
16
16
  }
package/dist/genie.js CHANGED
@@ -128,7 +128,7 @@ ${errCtx.stack}`;d.reject(err)}else d.resolve(msg)}});return sub.requestSubject=
128
128
  `}static header(){return`Test,Date,Lang,Version,Count,MsgPayload,Bytes,Millis,Async
129
129
  `}}exports.Metric=Metric;class Bench{constructor(nc,opts={msgs:1e5,size:128,subject:"",asyncRequests:!1,pub:!1,sub:!1,req:!1,rep:!1}){if(this.nc=nc,this.callbacks=opts.callbacks||!1,this.msgs=opts.msgs||0,this.size=opts.size||0,this.subject=opts.subject||nuid_1.nuid.next(),this.asyncRequests=opts.asyncRequests||!1,this.pub=opts.pub||!1,this.sub=opts.sub||!1,this.req=opts.req||!1,this.rep=opts.rep||!1,this.perf=new util_1.Perf,this.payload=this.size?new Uint8Array(this.size):types_1.Empty,!this.pub&&!this.sub&&!this.req&&!this.rep)throw Error("no bench option selected")}run(){return __awaiter(this,void 0,void 0,function*(){if(this.nc.closed().then((err)=>{if(err)throw new core_1.NatsError(`bench closed with an error: ${err.message}`,core_1.ErrorCode.Unknown,err)}),this.callbacks)yield this.runCallbacks();else yield this.runAsync();return this.processMetrics()})}processMetrics(){let nc=this.nc,{lang,version}=nc.protocol.transport;if(this.pub&&this.sub)this.perf.measure("pubsub","pubStart","subStop");if(this.req&&this.rep)this.perf.measure("reqrep","reqStart","reqStop");let measures=this.perf.getEntries(),pubsub=measures.find((m)=>m.name==="pubsub"),reqrep=measures.find((m)=>m.name==="reqrep"),req=measures.find((m)=>m.name==="req"),rep=measures.find((m)=>m.name==="rep"),pub=measures.find((m)=>m.name==="pub"),sub=measures.find((m)=>m.name==="sub"),stats=this.nc.stats(),metrics=[];if(pubsub){let{name,duration}=pubsub,m=new Metric(name,duration);m.msgs=this.msgs*2,m.bytes=stats.inBytes+stats.outBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}if(reqrep){let{name,duration}=reqrep,m=new Metric(name,duration);m.msgs=this.msgs*2,m.bytes=stats.inBytes+stats.outBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}if(pub){let{name,duration}=pub,m=new Metric(name,duration);m.msgs=this.msgs,m.bytes=stats.outBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}if(sub){let{name,duration}=sub,m=new Metric(name,duration);m.msgs=this.msgs,m.bytes=stats.inBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}if(rep){let{name,duration}=rep,m=new Metric(name,duration);m.msgs=this.msgs,m.bytes=stats.inBytes+stats.outBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}if(req){let{name,duration}=req,m=new Metric(name,duration);m.msgs=this.msgs,m.bytes=stats.inBytes+stats.outBytes,m.lang=lang,m.version=version,m.payload=this.payload.length,metrics.push(m)}return metrics}runCallbacks(){return __awaiter(this,void 0,void 0,function*(){let jobs=[];if(this.sub){let d=(0,util_1.deferred)();jobs.push(d);let i2=0;this.nc.subscribe(this.subject,{max:this.msgs,callback:()=>{if(i2++,i2===1)this.perf.mark("subStart");if(i2===this.msgs)this.perf.mark("subStop"),this.perf.measure("sub","subStart","subStop"),d.resolve()}})}if(this.rep){let d=(0,util_1.deferred)();jobs.push(d);let i2=0;this.nc.subscribe(this.subject,{max:this.msgs,callback:(_,m)=>{if(m.respond(this.payload),i2++,i2===1)this.perf.mark("repStart");if(i2===this.msgs)this.perf.mark("repStop"),this.perf.measure("rep","repStart","repStop"),d.resolve()}})}if(this.pub){let job=(()=>__awaiter(this,void 0,void 0,function*(){this.perf.mark("pubStart");for(let i2=0;i2<this.msgs;i2++)this.nc.publish(this.subject,this.payload);yield this.nc.flush(),this.perf.mark("pubStop"),this.perf.measure("pub","pubStart","pubStop")}))();jobs.push(job)}if(this.req){let job=(()=>__awaiter(this,void 0,void 0,function*(){if(this.asyncRequests){this.perf.mark("reqStart");let a=[];for(let i2=0;i2<this.msgs;i2++)a.push(this.nc.request(this.subject,this.payload,{timeout:20000}));yield Promise.all(a),this.perf.mark("reqStop"),this.perf.measure("req","reqStart","reqStop")}else{this.perf.mark("reqStart");for(let i2=0;i2<this.msgs;i2++)yield this.nc.request(this.subject);this.perf.mark("reqStop"),this.perf.measure("req","reqStart","reqStop")}}))();jobs.push(job)}yield Promise.all(jobs)})}runAsync(){return __awaiter(this,void 0,void 0,function*(){let jobs=[];if(this.rep){let first=!1,sub=this.nc.subscribe(this.subject,{max:this.msgs}),job=(()=>__awaiter(this,void 0,void 0,function*(){var _a,e_1,_b,_c;try{for(var _d=!0,sub_1=__asyncValues(sub),sub_1_1;sub_1_1=yield sub_1.next(),_a=sub_1_1.done,!_a;_d=!0){_c=sub_1_1.value,_d=!1;let m=_c;if(!first)this.perf.mark("repStart"),first=!0;m.respond(this.payload)}}catch(e_1_1){e_1={error:e_1_1}}finally{try{if(!_d&&!_a&&(_b=sub_1.return))yield _b.call(sub_1)}finally{if(e_1)throw e_1.error}}yield this.nc.flush(),this.perf.mark("repStop"),this.perf.measure("rep","repStart","repStop")}))();jobs.push(job)}if(this.sub){let first=!1,sub=this.nc.subscribe(this.subject,{max:this.msgs}),job=(()=>__awaiter(this,void 0,void 0,function*(){var _a,e_2,_b,_c;try{for(var _d=!0,sub_2=__asyncValues(sub),sub_2_1;sub_2_1=yield sub_2.next(),_a=sub_2_1.done,!_a;_d=!0){_c=sub_2_1.value,_d=!1;let _m=_c;if(!first)this.perf.mark("subStart"),first=!0}}catch(e_2_1){e_2={error:e_2_1}}finally{try{if(!_d&&!_a&&(_b=sub_2.return))yield _b.call(sub_2)}finally{if(e_2)throw e_2.error}}this.perf.mark("subStop"),this.perf.measure("sub","subStart","subStop")}))();jobs.push(job)}if(this.pub){let job=(()=>__awaiter(this,void 0,void 0,function*(){this.perf.mark("pubStart");for(let i2=0;i2<this.msgs;i2++)this.nc.publish(this.subject,this.payload);yield this.nc.flush(),this.perf.mark("pubStop"),this.perf.measure("pub","pubStart","pubStop")}))();jobs.push(job)}if(this.req){let job=(()=>__awaiter(this,void 0,void 0,function*(){if(this.asyncRequests){this.perf.mark("reqStart");let a=[];for(let i2=0;i2<this.msgs;i2++)a.push(this.nc.request(this.subject,this.payload,{timeout:20000}));yield Promise.all(a),this.perf.mark("reqStop"),this.perf.measure("req","reqStart","reqStop")}else{this.perf.mark("reqStart");for(let i2=0;i2<this.msgs;i2++)yield this.nc.request(this.subject);this.perf.mark("reqStop"),this.perf.measure("req","reqStart","reqStop")}}))();jobs.push(job)}yield Promise.all(jobs)})}}exports.Bench=Bench;function throughput(bytes,seconds){return`${humanizeBytes(bytes/seconds)}/sec`}function msgThroughput(msgs,seconds){return`${Math.floor(msgs/seconds)} msgs/sec`}function humanizeBytes(bytes,si=!1){let base=si?1000:1024,pre=si?["k","M","G","T","P","E"]:["K","M","G","T","P","E"],post=si?"iB":"B";if(bytes<base)return`${bytes.toFixed(2)} ${post}`;let exp=parseInt(Math.log(bytes)/Math.log(base)+""),index=parseInt(exp-1+"");return`${(bytes/Math.pow(base,exp)).toFixed(2)} ${pre[index]}${post}`}function humanizeNumber(n){return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}});var require_internal_mod=__commonJS((exports)=>{var __createBinding=exports&&exports.__createBinding||(Object.create?function(o,m,k,k2){if(k2===void 0)k2=k;var desc=Object.getOwnPropertyDescriptor(m,k);if(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable))desc={enumerable:!0,get:function(){return m[k]}};Object.defineProperty(o,k2,desc)}:function(o,m,k,k2){if(k2===void 0)k2=k;o[k2]=m[k]}),__exportStar=exports&&exports.__exportStar||function(m,exports2){for(var p in m)if(p!=="default"&&!Object.prototype.hasOwnProperty.call(exports2,p))__createBinding(exports2,m,p)};Object.defineProperty(exports,"__esModule",{value:!0});exports.parseIP=exports.isIP=exports.TE=exports.TD=exports.Metric=exports.Bench=exports.writeAll=exports.readAll=exports.MAX_SIZE=exports.DenoBuffer=exports.State=exports.Parser=exports.Kind=exports.QueuedIteratorImpl=exports.StringCodec=exports.JSONCodec=exports.usernamePasswordAuthenticator=exports.tokenAuthenticator=exports.nkeyAuthenticator=exports.jwtAuthenticator=exports.credsAuthenticator=exports.RequestOne=exports.checkUnsupportedOption=exports.checkOptions=exports.buildAuthenticator=exports.DataBuffer=exports.MuxSubscription=exports.Heartbeat=exports.MsgHdrsImpl=exports.headers=exports.canonicalMIMEHeaderKey=exports.timeout=exports.render=exports.nanos=exports.millis=exports.extend=exports.delay=exports.deferred=exports.deadline=exports.collect=exports.backoff=exports.ProtocolHandler=exports.INFO=exports.Connect=exports.setTransportFactory=exports.getResolveFn=exports.MsgImpl=exports.nuid=exports.Nuid=exports.NatsConnectionImpl=void 0;exports.Subscriptions=exports.SubscriptionImpl=exports.syncIterator=exports.ServiceVerb=exports.ServiceResponseType=exports.ServiceErrorHeader=exports.ServiceErrorCodeHeader=exports.ServiceError=exports.RequestStrategy=exports.NatsError=exports.Match=exports.isNatsError=exports.Events=exports.ErrorCode=exports.DebugEvents=exports.createInbox=exports.extractProtocolMessage=exports.Empty=exports.parseSemVer=exports.compare=exports.NoopKvCodecs=exports.defaultBucketOpts=exports.Bucket=exports.Base64KeyCodec=exports.TypedSubscription=void 0;var nats_1=require_nats();Object.defineProperty(exports,"NatsConnectionImpl",{enumerable:!0,get:function(){return nats_1.NatsConnectionImpl}});var nuid_1=require_nuid();Object.defineProperty(exports,"Nuid",{enumerable:!0,get:function(){return nuid_1.Nuid}});Object.defineProperty(exports,"nuid",{enumerable:!0,get:function(){return nuid_1.nuid}});var msg_1=require_msg();Object.defineProperty(exports,"MsgImpl",{enumerable:!0,get:function(){return msg_1.MsgImpl}});var transport_1=require_transport();Object.defineProperty(exports,"getResolveFn",{enumerable:!0,get:function(){return transport_1.getResolveFn}});Object.defineProperty(exports,"setTransportFactory",{enumerable:!0,get:function(){return transport_1.setTransportFactory}});var protocol_1=require_protocol();Object.defineProperty(exports,"Connect",{enumerable:!0,get:function(){return protocol_1.Connect}});Object.defineProperty(exports,"INFO",{enumerable:!0,get:function(){return protocol_1.INFO}});Object.defineProperty(exports,"ProtocolHandler",{enumerable:!0,get:function(){return protocol_1.ProtocolHandler}});var util_1=require_util();Object.defineProperty(exports,"backoff",{enumerable:!0,get:function(){return util_1.backoff}});Object.defineProperty(exports,"collect",{enumerable:!0,get:function(){return util_1.collect}});Object.defineProperty(exports,"deadline",{enumerable:!0,get:function(){return util_1.deadline}});Object.defineProperty(exports,"deferred",{enumerable:!0,get:function(){return util_1.deferred}});Object.defineProperty(exports,"delay",{enumerable:!0,get:function(){return util_1.delay}});Object.defineProperty(exports,"extend",{enumerable:!0,get:function(){return util_1.extend}});Object.defineProperty(exports,"millis",{enumerable:!0,get:function(){return util_1.millis}});Object.defineProperty(exports,"nanos",{enumerable:!0,get:function(){return util_1.nanos}});Object.defineProperty(exports,"render",{enumerable:!0,get:function(){return util_1.render}});Object.defineProperty(exports,"timeout",{enumerable:!0,get:function(){return util_1.timeout}});var headers_1=require_headers();Object.defineProperty(exports,"canonicalMIMEHeaderKey",{enumerable:!0,get:function(){return headers_1.canonicalMIMEHeaderKey}});Object.defineProperty(exports,"headers",{enumerable:!0,get:function(){return headers_1.headers}});Object.defineProperty(exports,"MsgHdrsImpl",{enumerable:!0,get:function(){return headers_1.MsgHdrsImpl}});var heartbeats_1=require_heartbeats();Object.defineProperty(exports,"Heartbeat",{enumerable:!0,get:function(){return heartbeats_1.Heartbeat}});var muxsubscription_1=require_muxsubscription();Object.defineProperty(exports,"MuxSubscription",{enumerable:!0,get:function(){return muxsubscription_1.MuxSubscription}});var databuffer_1=require_databuffer();Object.defineProperty(exports,"DataBuffer",{enumerable:!0,get:function(){return databuffer_1.DataBuffer}});var options_1=require_options();Object.defineProperty(exports,"buildAuthenticator",{enumerable:!0,get:function(){return options_1.buildAuthenticator}});Object.defineProperty(exports,"checkOptions",{enumerable:!0,get:function(){return options_1.checkOptions}});Object.defineProperty(exports,"checkUnsupportedOption",{enumerable:!0,get:function(){return options_1.checkUnsupportedOption}});var request_1=require_request();Object.defineProperty(exports,"RequestOne",{enumerable:!0,get:function(){return request_1.RequestOne}});var authenticator_1=require_authenticator();Object.defineProperty(exports,"credsAuthenticator",{enumerable:!0,get:function(){return authenticator_1.credsAuthenticator}});Object.defineProperty(exports,"jwtAuthenticator",{enumerable:!0,get:function(){return authenticator_1.jwtAuthenticator}});Object.defineProperty(exports,"nkeyAuthenticator",{enumerable:!0,get:function(){return authenticator_1.nkeyAuthenticator}});Object.defineProperty(exports,"tokenAuthenticator",{enumerable:!0,get:function(){return authenticator_1.tokenAuthenticator}});Object.defineProperty(exports,"usernamePasswordAuthenticator",{enumerable:!0,get:function(){return authenticator_1.usernamePasswordAuthenticator}});var codec_1=require_codec();Object.defineProperty(exports,"JSONCodec",{enumerable:!0,get:function(){return codec_1.JSONCodec}});Object.defineProperty(exports,"StringCodec",{enumerable:!0,get:function(){return codec_1.StringCodec}});__exportStar(require_nkeys2(),exports);var queued_iterator_1=require_queued_iterator();Object.defineProperty(exports,"QueuedIteratorImpl",{enumerable:!0,get:function(){return queued_iterator_1.QueuedIteratorImpl}});var parser_1=require_parser();Object.defineProperty(exports,"Kind",{enumerable:!0,get:function(){return parser_1.Kind}});Object.defineProperty(exports,"Parser",{enumerable:!0,get:function(){return parser_1.Parser}});Object.defineProperty(exports,"State",{enumerable:!0,get:function(){return parser_1.State}});var denobuffer_1=require_denobuffer();Object.defineProperty(exports,"DenoBuffer",{enumerable:!0,get:function(){return denobuffer_1.DenoBuffer}});Object.defineProperty(exports,"MAX_SIZE",{enumerable:!0,get:function(){return denobuffer_1.MAX_SIZE}});Object.defineProperty(exports,"readAll",{enumerable:!0,get:function(){return denobuffer_1.readAll}});Object.defineProperty(exports,"writeAll",{enumerable:!0,get:function(){return denobuffer_1.writeAll}});var bench_1=require_bench();Object.defineProperty(exports,"Bench",{enumerable:!0,get:function(){return bench_1.Bench}});Object.defineProperty(exports,"Metric",{enumerable:!0,get:function(){return bench_1.Metric}});var encoders_1=require_encoders();Object.defineProperty(exports,"TD",{enumerable:!0,get:function(){return encoders_1.TD}});Object.defineProperty(exports,"TE",{enumerable:!0,get:function(){return encoders_1.TE}});var ipparser_1=require_ipparser();Object.defineProperty(exports,"isIP",{enumerable:!0,get:function(){return ipparser_1.isIP}});Object.defineProperty(exports,"parseIP",{enumerable:!0,get:function(){return ipparser_1.parseIP}});var typedsub_1=require_typedsub();Object.defineProperty(exports,"TypedSubscription",{enumerable:!0,get:function(){return typedsub_1.TypedSubscription}});var kv_1=require_kv();Object.defineProperty(exports,"Base64KeyCodec",{enumerable:!0,get:function(){return kv_1.Base64KeyCodec}});Object.defineProperty(exports,"Bucket",{enumerable:!0,get:function(){return kv_1.Bucket}});Object.defineProperty(exports,"defaultBucketOpts",{enumerable:!0,get:function(){return kv_1.defaultBucketOpts}});Object.defineProperty(exports,"NoopKvCodecs",{enumerable:!0,get:function(){return kv_1.NoopKvCodecs}});var semver_1=require_semver();Object.defineProperty(exports,"compare",{enumerable:!0,get:function(){return semver_1.compare}});Object.defineProperty(exports,"parseSemVer",{enumerable:!0,get:function(){return semver_1.parseSemVer}});var types_1=require_types();Object.defineProperty(exports,"Empty",{enumerable:!0,get:function(){return types_1.Empty}});var transport_2=require_transport();Object.defineProperty(exports,"extractProtocolMessage",{enumerable:!0,get:function(){return transport_2.extractProtocolMessage}});var core_1=require_core();Object.defineProperty(exports,"createInbox",{enumerable:!0,get:function(){return core_1.createInbox}});Object.defineProperty(exports,"DebugEvents",{enumerable:!0,get:function(){return core_1.DebugEvents}});Object.defineProperty(exports,"ErrorCode",{enumerable:!0,get:function(){return core_1.ErrorCode}});Object.defineProperty(exports,"Events",{enumerable:!0,get:function(){return core_1.Events}});Object.defineProperty(exports,"isNatsError",{enumerable:!0,get:function(){return core_1.isNatsError}});Object.defineProperty(exports,"Match",{enumerable:!0,get:function(){return core_1.Match}});Object.defineProperty(exports,"NatsError",{enumerable:!0,get:function(){return core_1.NatsError}});Object.defineProperty(exports,"RequestStrategy",{enumerable:!0,get:function(){return core_1.RequestStrategy}});Object.defineProperty(exports,"ServiceError",{enumerable:!0,get:function(){return core_1.ServiceError}});Object.defineProperty(exports,"ServiceErrorCodeHeader",{enumerable:!0,get:function(){return core_1.ServiceErrorCodeHeader}});Object.defineProperty(exports,"ServiceErrorHeader",{enumerable:!0,get:function(){return core_1.ServiceErrorHeader}});Object.defineProperty(exports,"ServiceResponseType",{enumerable:!0,get:function(){return core_1.ServiceResponseType}});Object.defineProperty(exports,"ServiceVerb",{enumerable:!0,get:function(){return core_1.ServiceVerb}});Object.defineProperty(exports,"syncIterator",{enumerable:!0,get:function(){return core_1.syncIterator}});var protocol_2=require_protocol();Object.defineProperty(exports,"SubscriptionImpl",{enumerable:!0,get:function(){return protocol_2.SubscriptionImpl}});Object.defineProperty(exports,"Subscriptions",{enumerable:!0,get:function(){return protocol_2.Subscriptions}})});var require_internal_mod2=__commonJS((exports)=>{Object.defineProperty(exports,"__esModule",{value:!0});exports.ConsumerEvents=exports.ConsumerDebugEvents=exports.StoreCompression=exports.StorageType=exports.RetentionPolicy=exports.ReplayPolicy=exports.DiscardPolicy=exports.DeliverPolicy=exports.AckPolicy=exports.RepublishHeaders=exports.KvWatchInclude=exports.JsHeaders=exports.isConsumerOptsBuilder=exports.DirectMsgHeaders=exports.consumerOpts=exports.AdvisoryKind=exports.isHeartbeatMsg=exports.isFlowControlMsg=exports.checkJsError=void 0;var jsutil_1=require_jsutil();Object.defineProperty(exports,"checkJsError",{enumerable:!0,get:function(){return jsutil_1.checkJsError}});Object.defineProperty(exports,"isFlowControlMsg",{enumerable:!0,get:function(){return jsutil_1.isFlowControlMsg}});Object.defineProperty(exports,"isHeartbeatMsg",{enumerable:!0,get:function(){return jsutil_1.isHeartbeatMsg}});var types_1=require_types2();Object.defineProperty(exports,"AdvisoryKind",{enumerable:!0,get:function(){return types_1.AdvisoryKind}});Object.defineProperty(exports,"consumerOpts",{enumerable:!0,get:function(){return types_1.consumerOpts}});Object.defineProperty(exports,"DirectMsgHeaders",{enumerable:!0,get:function(){return types_1.DirectMsgHeaders}});Object.defineProperty(exports,"isConsumerOptsBuilder",{enumerable:!0,get:function(){return types_1.isConsumerOptsBuilder}});Object.defineProperty(exports,"JsHeaders",{enumerable:!0,get:function(){return types_1.JsHeaders}});Object.defineProperty(exports,"KvWatchInclude",{enumerable:!0,get:function(){return types_1.KvWatchInclude}});Object.defineProperty(exports,"RepublishHeaders",{enumerable:!0,get:function(){return types_1.RepublishHeaders}});var jsapi_types_1=require_jsapi_types();Object.defineProperty(exports,"AckPolicy",{enumerable:!0,get:function(){return jsapi_types_1.AckPolicy}});Object.defineProperty(exports,"DeliverPolicy",{enumerable:!0,get:function(){return jsapi_types_1.DeliverPolicy}});Object.defineProperty(exports,"DiscardPolicy",{enumerable:!0,get:function(){return jsapi_types_1.DiscardPolicy}});Object.defineProperty(exports,"ReplayPolicy",{enumerable:!0,get:function(){return jsapi_types_1.ReplayPolicy}});Object.defineProperty(exports,"RetentionPolicy",{enumerable:!0,get:function(){return jsapi_types_1.RetentionPolicy}});Object.defineProperty(exports,"StorageType",{enumerable:!0,get:function(){return jsapi_types_1.StorageType}});Object.defineProperty(exports,"StoreCompression",{enumerable:!0,get:function(){return jsapi_types_1.StoreCompression}});var consumer_1=require_consumer();Object.defineProperty(exports,"ConsumerDebugEvents",{enumerable:!0,get:function(){return consumer_1.ConsumerDebugEvents}});Object.defineProperty(exports,"ConsumerEvents",{enumerable:!0,get:function(){return consumer_1.ConsumerEvents}})});var require_nats_base_client=__commonJS((exports)=>{var __createBinding=exports&&exports.__createBinding||(Object.create?function(o,m,k,k2){if(k2===void 0)k2=k;var desc=Object.getOwnPropertyDescriptor(m,k);if(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable))desc={enumerable:!0,get:function(){return m[k]}};Object.defineProperty(o,k2,desc)}:function(o,m,k,k2){if(k2===void 0)k2=k;o[k2]=m[k]}),__exportStar=exports&&exports.__exportStar||function(m,exports2){for(var p in m)if(p!=="default"&&!Object.prototype.hasOwnProperty.call(exports2,p))__createBinding(exports2,m,p)};Object.defineProperty(exports,"__esModule",{value:!0});__exportStar(require_internal_mod(),exports);__exportStar(require_internal_mod2(),exports)});var require_node_transport=__commonJS((exports)=>{var __awaiter=exports&&exports.__awaiter||function(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P(function(resolve5){resolve5(value)})}return new(P||(P=Promise))(function(resolve5,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator.throw(value))}catch(e){reject(e)}}function step(result){result.done?resolve5(result.value):adopt(result.value).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())})},__await=exports&&exports.__await||function(v){return this instanceof __await?(this.v=v,this):new __await(v)},__asyncGenerator=exports&&exports.__asyncGenerator||function(thisArg,_arguments,generator){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var g=generator.apply(thisArg,_arguments||[]),i2,q=[];return i2=Object.create((typeof AsyncIterator==="function"?AsyncIterator:Object).prototype),verb("next"),verb("throw"),verb("return",awaitReturn),i2[Symbol.asyncIterator]=function(){return this},i2;function awaitReturn(f){return function(v){return Promise.resolve(v).then(f,reject)}}function verb(n,f){if(g[n]){if(i2[n]=function(v){return new Promise(function(a,b){q.push([n,v,a,b])>1||resume(n,v)})},f)i2[n]=f(i2[n])}}function resume(n,v){try{step(g[n](v))}catch(e){settle(q[0][3],e)}}function step(r){r.value instanceof __await?Promise.resolve(r.value.v).then(fulfill,reject):settle(q[0][2],r)}function fulfill(value){resume("next",value)}function reject(value){resume("throw",value)}function settle(f,v){if(f(v),q.shift(),q.length)resume(q[0][0],q[0][1])}};Object.defineProperty(exports,"__esModule",{value:!0});exports.NodeTransport=void 0;exports.nodeResolveHost=nodeResolveHost;var nats_base_client_1=require_nats_base_client(),net_1=__require("net"),util_1=require_util(),tls_1=__require("tls"),{resolve:resolve4}=__require("path"),{readFile:readFile4,existsSync:existsSync14}=__require("fs"),dns=__require("dns"),VERSION2="2.29.3",LANG="nats.js";class NodeTransport{constructor(){this.yields=[],this.signal=(0,nats_base_client_1.deferred)(),this.closedNotification=(0,nats_base_client_1.deferred)(),this.connected=!1,this.tlsName="",this.done=!1,this.lang=LANG,this.version=VERSION2}connect(hp,options){return __awaiter(this,void 0,void 0,function*(){this.tlsName=hp.tlsName,this.options=options;let{tls}=this.options,{handshakeFirst}=tls||{};try{if(handshakeFirst===!0)this.socket=yield this.tlsFirst(hp);else this.socket=yield this.dial(hp);let info=yield this.peekInfo();(0,nats_base_client_1.checkOptions)(info,options);let{tls_required:tlsRequired,tls_available:tlsAvailable}=info,desired=tlsAvailable===!0&&options.tls!==null;if(!handshakeFirst&&(tlsRequired||desired))this.socket=yield this.startTLS();if(tlsRequired&&this.socket.encrypted!==!0)throw new nats_base_client_1.NatsError("tls",nats_base_client_1.ErrorCode.ServerOptionNotAvailable);return this.connected=!0,this.setupHandlers(),this.signal.resolve(),Promise.resolve()}catch(err){if(!err)err=nats_base_client_1.NatsError.errorForCode(nats_base_client_1.ErrorCode.ConnectionRefused,Error("node provided an undefined error!"));let{code}=err,perr=code==="ECONNREFUSED"?nats_base_client_1.NatsError.errorForCode(nats_base_client_1.ErrorCode.ConnectionRefused,err):err;if(this.socket)this.socket.destroy();throw perr}})}dial(hp){let d=(0,nats_base_client_1.deferred)(),dialError,socket=(0,net_1.createConnection)(hp.port,hp.hostname,()=>{d.resolve(socket),socket.removeAllListeners()});return socket.on("error",(err)=>{dialError=err}),socket.on("close",()=>{socket.removeAllListeners(),d.reject(dialError)}),socket.setNoDelay(!0),d}get isClosed(){return this.done}close(err){return this._closed(err,!1)}peekInfo(){let d=(0,nats_base_client_1.deferred)(),peekError;return this.socket.on("data",(frame)=>{this.yields.push(frame);let t=nats_base_client_1.DataBuffer.concat(...this.yields),pm=(0,nats_base_client_1.extractProtocolMessage)(t);if(pm!=="")try{let m=nats_base_client_1.INFO.exec(pm);if(!m)throw Error("unexpected response from server");let info=JSON.parse(m[1]);d.resolve(info)}catch(err){d.reject(err)}finally{this.socket.removeAllListeners()}}),this.socket.on("error",(err)=>{peekError=err}),this.socket.on("close",()=>{this.socket.removeAllListeners(),d.reject(peekError)}),d}loadFile(fn){if(!fn)return Promise.resolve();let d=(0,nats_base_client_1.deferred)();try{if(fn=resolve4(fn),!existsSync14(fn))d.reject(Error(`${fn} doesn't exist`));readFile4(fn,(err,data)=>{if(err)return d.reject(err);d.resolve(data)})}catch(err){d.reject(err)}return d}loadClientCerts(){return __awaiter(this,void 0,void 0,function*(){let tlsOpts={},{certFile,cert,caFile,ca,keyFile,key}=this.options.tls;try{if(certFile){let data=yield this.loadFile(certFile);if(data)tlsOpts.cert=data}else if(cert)tlsOpts.cert=cert;if(keyFile){let data=yield this.loadFile(keyFile);if(data)tlsOpts.key=data}else if(key)tlsOpts.key=key;if(caFile){let data=yield this.loadFile(caFile);if(data)tlsOpts.ca=[data]}else if(ca)tlsOpts.ca=ca;return Promise.resolve(tlsOpts)}catch(err){return Promise.reject(err)}})}tlsFirst(hp){return __awaiter(this,void 0,void 0,function*(){let tlsError,tlsOpts={servername:this.tlsName,rejectUnauthorized:!0};if(this.socket)tlsOpts.socket=this.socket;if(typeof this.options.tls==="object")try{let certOpts=(yield this.loadClientCerts())||{};tlsOpts=(0,util_1.extend)(tlsOpts,this.options.tls,certOpts)}catch(err){return Promise.reject(new nats_base_client_1.NatsError(err.message,nats_base_client_1.ErrorCode.Tls,err))}let d=(0,nats_base_client_1.deferred)();try{let tlsSocket=(0,tls_1.connect)(hp.port,hp.hostname,tlsOpts,()=>{tlsSocket.removeAllListeners(),d.resolve(tlsSocket)});tlsSocket.on("error",(err)=>{tlsError=err}),tlsSocket.on("secureConnect",()=>{if(tlsOpts.rejectUnauthorized===!1)return;if(!tlsSocket.authorized)throw tlsSocket.authorizationError}),tlsSocket.on("close",()=>{d.reject(tlsError),tlsSocket.removeAllListeners()}),tlsSocket.setNoDelay(!0)}catch(err){d.reject(nats_base_client_1.NatsError.errorForCode(nats_base_client_1.ErrorCode.Tls,err))}return d})}startTLS(){return __awaiter(this,void 0,void 0,function*(){let tlsError,tlsOpts={socket:this.socket,servername:this.tlsName,rejectUnauthorized:!0};if(typeof this.options.tls==="object")try{let certOpts=(yield this.loadClientCerts())||{};tlsOpts=(0,util_1.extend)(tlsOpts,this.options.tls,certOpts)}catch(err){return Promise.reject(new nats_base_client_1.NatsError(err.message,nats_base_client_1.ErrorCode.Tls,err))}let d=(0,nats_base_client_1.deferred)();try{let tlsSocket=(0,tls_1.connect)(tlsOpts,()=>{tlsSocket.removeAllListeners(),d.resolve(tlsSocket)});tlsSocket.on("error",(err)=>{tlsError=err}),tlsSocket.on("secureConnect",()=>{if(tlsOpts.rejectUnauthorized===!1)return;if(!tlsSocket.authorized)throw tlsSocket.authorizationError}),tlsSocket.on("close",()=>{d.reject(tlsError),tlsSocket.removeAllListeners()})}catch(err){d.reject(nats_base_client_1.NatsError.errorForCode(nats_base_client_1.ErrorCode.Tls,err))}return d})}setupHandlers(){let connError;this.socket.on("data",(frame)=>{return this.yields.push(frame),this.signal.resolve()}),this.socket.on("error",(err)=>{connError=err}),this.socket.on("end",()=>{var _a,_b;if((_a=this.socket)===null||_a===void 0?void 0:_a.destroyed)return;(_b=this.socket)===null||_b===void 0||_b.write(new Uint8Array(0),()=>{var _a2;(_a2=this.socket)===null||_a2===void 0||_a2.end()})}),this.socket.on("close",()=>{this._closed(connError,!1)})}[Symbol.asyncIterator](){return this.iterate()}iterate(){return __asyncGenerator(this,arguments,function*(){let debug=this.options.debug;while(!0){if(this.yields.length===0)yield __await(this.signal);let yields=this.yields;this.yields=[];for(let i2=0;i2<yields.length;i2++){if(debug)console.info(`> ${(0,nats_base_client_1.render)(yields[i2])}`);yield yield __await(yields[i2])}if(this.done)break;else if(this.yields.length===0)yields.length=0,this.yields=yields,this.signal=(0,nats_base_client_1.deferred)()}})}discard(){}disconnect(){this._closed(void 0,!0).then().catch()}isEncrypted(){return this.socket instanceof tls_1.TLSSocket}_send(frame){if(this.isClosed||this.socket===void 0)return Promise.resolve();if(this.options.debug)console.info(`< ${(0,nats_base_client_1.render)(frame)}`);let d=(0,nats_base_client_1.deferred)();try{this.socket.write(frame,(err)=>{if(err){if(this.options.debug)console.error(`!!! ${(0,nats_base_client_1.render)(frame)}: ${err}`);return d.reject(err)}return d.resolve()})}catch(err){if(this.options.debug)console.error(`!!! ${(0,nats_base_client_1.render)(frame)}: ${err}`);d.reject(err)}return d}send(frame){this._send(frame).catch((_err)=>{})}_closed(err_1){return __awaiter(this,arguments,void 0,function*(err,internal=!0){if(!this.connected)return;if(this.done)return;if(this.closeError=err,!err&&this.socket&&internal)try{yield this._send(new TextEncoder().encode(""))}catch(err2){if(this.options.debug)console.log("transport close terminated with an error",err2)}try{if(this.socket)this.socket.removeAllListeners(),this.socket.destroy(),this.socket=void 0}catch(err2){console.log(err2)}this.done=!0,this.closedNotification.resolve(this.closeError)})}closed(){return this.closedNotification}}exports.NodeTransport=NodeTransport;function nodeResolveHost(s){return __awaiter(this,void 0,void 0,function*(){let a=(0,nats_base_client_1.deferred)(),aaaa=(0,nats_base_client_1.deferred)();dns.resolve4(s,(err,records)=>{if(err)a.resolve(err);else a.resolve(records)}),dns.resolve6(s,(err,records)=>{if(err)aaaa.resolve(err);else aaaa.resolve(records)});let ips=[],da=yield a;if(Array.isArray(da))ips.push(...da);let daaaa=yield aaaa;if(Array.isArray(daaaa))ips.push(...daaaa);if(ips.length===0)ips.push(s);return ips})}});var require_connect=__commonJS((exports)=>{Object.defineProperty(exports,"__esModule",{value:!0});exports.connect=connect;var node_transport_1=require_node_transport(),nats_base_client_1=require_nats_base_client();function connect(opts={}){return(0,nats_base_client_1.setTransportFactory)({factory:()=>{return new node_transport_1.NodeTransport},dnsResolveFn:node_transport_1.nodeResolveHost}),nats_base_client_1.NatsConnectionImpl.connect(opts)}});var require_mod3=__commonJS((exports)=>{Object.defineProperty(exports,"__esModule",{value:!0});exports.consumerOpts=exports.StoreCompression=exports.StorageType=exports.RetentionPolicy=exports.RepublishHeaders=exports.ReplayPolicy=exports.KvWatchInclude=exports.JsHeaders=exports.DiscardPolicy=exports.DirectMsgHeaders=exports.DeliverPolicy=exports.ConsumerEvents=exports.ConsumerDebugEvents=exports.AdvisoryKind=exports.AckPolicy=exports.isHeartbeatMsg=exports.isFlowControlMsg=exports.checkJsError=void 0;var internal_mod_1=require_internal_mod2();Object.defineProperty(exports,"checkJsError",{enumerable:!0,get:function(){return internal_mod_1.checkJsError}});Object.defineProperty(exports,"isFlowControlMsg",{enumerable:!0,get:function(){return internal_mod_1.isFlowControlMsg}});Object.defineProperty(exports,"isHeartbeatMsg",{enumerable:!0,get:function(){return internal_mod_1.isHeartbeatMsg}});var internal_mod_2=require_internal_mod2();Object.defineProperty(exports,"AckPolicy",{enumerable:!0,get:function(){return internal_mod_2.AckPolicy}});Object.defineProperty(exports,"AdvisoryKind",{enumerable:!0,get:function(){return internal_mod_2.AdvisoryKind}});Object.defineProperty(exports,"ConsumerDebugEvents",{enumerable:!0,get:function(){return internal_mod_2.ConsumerDebugEvents}});Object.defineProperty(exports,"ConsumerEvents",{enumerable:!0,get:function(){return internal_mod_2.ConsumerEvents}});Object.defineProperty(exports,"DeliverPolicy",{enumerable:!0,get:function(){return internal_mod_2.DeliverPolicy}});Object.defineProperty(exports,"DirectMsgHeaders",{enumerable:!0,get:function(){return internal_mod_2.DirectMsgHeaders}});Object.defineProperty(exports,"DiscardPolicy",{enumerable:!0,get:function(){return internal_mod_2.DiscardPolicy}});Object.defineProperty(exports,"JsHeaders",{enumerable:!0,get:function(){return internal_mod_2.JsHeaders}});Object.defineProperty(exports,"KvWatchInclude",{enumerable:!0,get:function(){return internal_mod_2.KvWatchInclude}});Object.defineProperty(exports,"ReplayPolicy",{enumerable:!0,get:function(){return internal_mod_2.ReplayPolicy}});Object.defineProperty(exports,"RepublishHeaders",{enumerable:!0,get:function(){return internal_mod_2.RepublishHeaders}});Object.defineProperty(exports,"RetentionPolicy",{enumerable:!0,get:function(){return internal_mod_2.RetentionPolicy}});Object.defineProperty(exports,"StorageType",{enumerable:!0,get:function(){return internal_mod_2.StorageType}});Object.defineProperty(exports,"StoreCompression",{enumerable:!0,get:function(){return internal_mod_2.StoreCompression}});var types_1=require_types2();Object.defineProperty(exports,"consumerOpts",{enumerable:!0,get:function(){return types_1.consumerOpts}})});var require_mod4=__commonJS((exports)=>{var __createBinding=exports&&exports.__createBinding||(Object.create?function(o,m,k,k2){if(k2===void 0)k2=k;var desc=Object.getOwnPropertyDescriptor(m,k);if(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable))desc={enumerable:!0,get:function(){return m[k]}};Object.defineProperty(o,k2,desc)}:function(o,m,k,k2){if(k2===void 0)k2=k;o[k2]=m[k]}),__exportStar=exports&&exports.__exportStar||function(m,exports2){for(var p in m)if(p!=="default"&&!Object.prototype.hasOwnProperty.call(exports2,p))__createBinding(exports2,m,p)};Object.defineProperty(exports,"__esModule",{value:!0});exports.connect=void 0;if(typeof TextEncoder>"u"){let{TextEncoder:TextEncoder2,TextDecoder:TextDecoder2}=__require("util");global.TextEncoder=TextEncoder2,global.TextDecoder=TextDecoder2}if(typeof globalThis.crypto>"u"){let c=__require("crypto");global.crypto=c.webcrypto}if(typeof globalThis.ReadableStream>"u"){let chunks=process.versions.node.split(".");if(parseInt(chunks[0])>=16){let streams=__require("stream/web");global.ReadableStream=streams.ReadableStream}}var connect_1=require_connect();Object.defineProperty(exports,"connect",{enumerable:!0,get:function(){return connect_1.connect}});__exportStar(require_mod2(),exports);__exportStar(require_mod3(),exports)});var exports_nats_client={};__export(exports_nats_client,{subscribe:()=>subscribe,publish:()=>publish,isAvailable:()=>isAvailable,close:()=>close,_resetForTesting:()=>_resetForTesting});function getNatsUrl(){return process.env.GENIE_NATS_URL||"nats://localhost:4222"}function warnOnce(key,message){if(!state[key])state[key]=!0,console.warn(`[genie:nats] ${message}`)}async function importNats(){try{return await Promise.resolve().then(() => __toESM(require_mod4(),1))}catch{return warnOnce("warnedMissingPackage","nats package not installed \u2014 real-time features disabled"),null}}async function ensureConnection(){if(state.connection&&!state.connection.isClosed())return resetIdleTimer(),!0;if(state.connecting)return state.connecting;return state.connecting=(async()=>{try{let natsModule=await importNats();if(!natsModule)return!1;return state.connection=await natsModule.connect({servers:getNatsUrl(),maxReconnectAttempts:2,reconnectTimeWait:500,timeout:2000}),state.codec=natsModule.JSONCodec(),state.warnedUnavailable=!1,resetIdleTimer(),!0}catch{return state.connection=null,state.codec=null,warnOnce("warnedUnavailable",`NATS not available at ${getNatsUrl()}`),!1}finally{state.connecting=null}})(),state.connecting}function resetIdleTimer(){if(state.idleTimer)clearTimeout(state.idleTimer);if(state.activeSubscriptions>0)return;state.idleTimer=setTimeout(()=>{if(state.activeSubscriptions===0)close().catch(()=>{})},500)}async function publish(subject,data){if(!await ensureConnection()||!state.connection||!state.codec)return;try{state.connection.publish(subject,state.codec.encode(data))}catch{}resetIdleTimer()}async function subscribe(subject,callback){let noop={unsubscribe:()=>{}};if(!await ensureConnection()||!state.connection||!state.codec)return noop;try{let sub=state.connection.subscribe(subject),codec=state.codec;if(state.activeSubscriptions++,state.idleTimer)clearTimeout(state.idleTimer),state.idleTimer=null;return(async()=>{try{for await(let msg of sub)try{callback(msg.subject,codec.decode(msg.data))}catch{}}catch{}})(),{unsubscribe:()=>{try{sub.unsubscribe()}catch{}state.activeSubscriptions=Math.max(0,state.activeSubscriptions-1),resetIdleTimer()}}}catch{return noop}}async function isAvailable(){return ensureConnection()}async function close(){if(state.idleTimer)clearTimeout(state.idleTimer),state.idleTimer=null;if(state.connection){try{await state.connection.drain()}catch{try{await state.connection.close()}catch{}}state.connection=null,state.codec=null}}function _resetForTesting(){if(state.connection=null,state.codec=null,state.connecting=null,state.warnedUnavailable=!1,state.warnedMissingPackage=!1,state.activeSubscriptions=0,state.idleTimer)clearTimeout(state.idleTimer);state.idleTimer=null}var state;var init_nats_client=__esm(()=>{state={connection:null,codec:null,connecting:null,warnedUnavailable:!1,warnedMissingPackage:!1,activeSubscriptions:0,idleTimer:null}});function isBlockingEvent(event){return BLOCKING_EVENTS.has(event)}var DISPATCHED_EVENTS,BLOCKING_EVENTS;var init_types2=__esm(()=>{DISPATCHED_EVENTS=["PreToolUse","PostToolUse","SessionStart","SessionEnd","TeammateIdle","TaskCompleted"],BLOCKING_EVENTS=new Set(["PreToolUse","UserPromptSubmit","TeammateIdle","TaskCompleted","PermissionRequest"])});function buildLayoutCommand(windowTarget,mode="mosaic"){return`select-layout -t '${windowTarget}' ${mode==="vertical"?"even-horizontal":"tiled"}`}function resolveLayoutMode(layoutFlag){if(layoutFlag==="vertical")return"vertical";return"mosaic"}import{randomUUID}from"crypto";var native_default;var init_native=__esm(()=>{native_default={randomUUID}});import{randomFillSync}from"crypto";function rng(){if(poolPtr>rnds8Pool.length-16)randomFillSync(rnds8Pool),poolPtr=0;return rnds8Pool.slice(poolPtr,poolPtr+=16)}var rnds8Pool,poolPtr;var init_rng=__esm(()=>{rnds8Pool=new Uint8Array(256),poolPtr=rnds8Pool.length});function unsafeStringify(arr,offset=0){return(byteToHex[arr[offset+0]]+byteToHex[arr[offset+1]]+byteToHex[arr[offset+2]]+byteToHex[arr[offset+3]]+"-"+byteToHex[arr[offset+4]]+byteToHex[arr[offset+5]]+"-"+byteToHex[arr[offset+6]]+byteToHex[arr[offset+7]]+"-"+byteToHex[arr[offset+8]]+byteToHex[arr[offset+9]]+"-"+byteToHex[arr[offset+10]]+byteToHex[arr[offset+11]]+byteToHex[arr[offset+12]]+byteToHex[arr[offset+13]]+byteToHex[arr[offset+14]]+byteToHex[arr[offset+15]]).toLowerCase()}var byteToHex;var init_stringify=__esm(()=>{byteToHex=[];for(let i2=0;i2<256;++i2)byteToHex.push((i2+256).toString(16).slice(1))});function v4(options,buf,offset){if(native_default.randomUUID&&!buf&&!options)return native_default.randomUUID();options=options||{};let rnds=options.random??options.rng?.()??rng();if(rnds.length<16)throw Error("Random bytes length must be >= 16");if(rnds[6]=rnds[6]&15|64,rnds[8]=rnds[8]&63|128,buf){if(offset=offset||0,offset<0||offset+16>buf.length)throw RangeError(`UUID byte range ${offset}:${offset+15} is out of buffer bounds`);for(let i2=0;i2<16;++i2)buf[offset+i2]=rnds[i2];return buf}return unsafeStringify(rnds)}var v4_default;var init_v4=__esm(()=>{init_native();init_rng();init_stringify();v4_default=v4});var init_esm7=__esm(()=>{init_v4()});import{appendFile,mkdir as mkdir5,readFile as readFile4,writeFile as writeFile4}from"fs/promises";import path,{join as join15}from"path";function mailboxDir(repoPath){return join15(repoPath,".genie","mailbox")}function mailboxFilePath(repoPath,workerId){let safeId=path.basename(workerId);return join15(mailboxDir(repoPath),`${safeId}.json`)}function outboxFilePath(repoPath,workerId){let safeId=path.basename(workerId);return join15(mailboxDir(repoPath),`${safeId}-sent.jsonl`)}async function loadMailbox(repoPath,workerId){try{let content=await readFile4(mailboxFilePath(repoPath,workerId),"utf-8");return JSON.parse(content)}catch{return{workerId,messages:[],lastUpdated:new Date().toISOString()}}}async function saveMailbox(repoPath,mailbox){let dir=mailboxDir(repoPath);await mkdir5(dir,{recursive:!0}),mailbox.lastUpdated=new Date().toISOString(),await writeFile4(mailboxFilePath(repoPath,mailbox.workerId),JSON.stringify(mailbox,null,2))}function generateMessageId(){return`msg-${v4_default()}`}async function send(repoPath,from,to,body){await mkdir5(mailboxDir(repoPath),{recursive:!0});let release=await acquireLock(mailboxFilePath(repoPath,to));try{let mailbox=await loadMailbox(repoPath,to),message={id:generateMessageId(),from,to,body,createdAt:new Date().toISOString(),read:!1,deliveredAt:null};mailbox.messages.push(message),await saveMailbox(repoPath,mailbox),await appendFile(outboxFilePath(repoPath,from),`${JSON.stringify(message)}
130
130
  `);try{let{publish:publish2}=await Promise.resolve().then(() => (init_nats_client(),exports_nats_client));await publish2(`genie.msg.${to}`,{timestamp:message.createdAt,kind:"message",agent:from,direction:"out",peer:to,text:body,data:{messageId:message.id,from,to},source:"mailbox"})}catch{}return message}finally{await release()}}async function inbox(repoPath,workerId){return(await loadMailbox(repoPath,workerId)).messages}async function readOutbox(repoPath,workerId){try{let lines=(await readFile4(outboxFilePath(repoPath,workerId),"utf-8")).trim().split(`
131
- `).filter(Boolean),messages=[];for(let line of lines)try{messages.push(JSON.parse(line))}catch{}return messages}catch{return[]}}async function markDelivered(repoPath,workerId,messageId){await mkdir5(mailboxDir(repoPath),{recursive:!0});let release=await acquireLock(mailboxFilePath(repoPath,workerId));try{let mailbox=await loadMailbox(repoPath,workerId),msg=mailbox.messages.find((m)=>m.id===messageId);if(!msg)return!1;return msg.deliveredAt=new Date().toISOString(),await saveMailbox(repoPath,mailbox),!0}finally{await release()}}function toNativeInboxMessage(msg,color="blue"){let words=msg.body.split(/\s+/),summary=words.slice(0,8).join(" ")+(words.length>8?"...":"");return{from:msg.from,text:msg.body,summary,timestamp:msg.createdAt,color,read:!1}}var init_mailbox=__esm(()=>{init_esm7();init_file_lock()});var exports_team_manager={};__export(exports_team_manager,{validateBranchName:()=>validateBranchName,updateTeamConfig:()=>updateTeamConfig,setTeamStatus:()=>setTeamStatus,pruneStaleWorktrees:()=>pruneStaleWorktrees,listTeams:()=>listTeams2,listMembers:()=>listMembers,killTeamMembers:()=>killTeamMembers,hireAgent:()=>hireAgent,getTeam:()=>getTeam2,fireAgent:()=>fireAgent,disbandTeam:()=>disbandTeam,createTeam:()=>createTeam});import{existsSync as existsSync14}from"fs";import{mkdir as mkdir6,readFile as readFile5,readdir as readdir2,rm as rm3,unlink as unlink4,writeFile as writeFile5}from"fs/promises";import{homedir as homedir13}from"os";import path2,{join as join16}from"path";var{$:$3}=globalThis.Bun;function getGenieDir2(){return process.env.GENIE_HOME??join16(homedir13(),".genie")}function teamsDir(){return join16(getGenieDir2(),"teams")}function safeFileName(name){return name.replace(/\//g,"--")}function teamFilePath(name){let safeName=safeFileName(path2.basename(name)===name?name:name);return join16(teamsDir(),`${safeName}.json`)}function getWorktreeBase(repoPath){let base=loadGenieConfigSync().terminal?.worktreeBase;if(base&&base!==".worktrees"){if(path2.isAbsolute(base))return base;return join16(repoPath,base)}let projectName=path2.basename(repoPath);return join16(getGenieDir2(),"worktrees",projectName)}function validateBranchName(name){let errors3=[];if(/\s/.test(name))errors3.push("contains spaces");if(name.includes(".."))errors3.push('contains ".."');if(name.includes("~"))errors3.push('contains "~"');if(name.includes("^"))errors3.push('contains "^"');if(name.includes(":"))errors3.push('contains ":"');if(name.includes("?"))errors3.push('contains "?"');if(name.includes("*"))errors3.push('contains "*"');if(name.includes("["))errors3.push('contains "["');if(name.includes("\\"))errors3.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(name))errors3.push("contains control characters");if(name.endsWith(".lock"))errors3.push('ends with ".lock"');if(name.endsWith("/"))errors3.push('ends with "/"');if(name.endsWith("."))errors3.push('ends with "."');if(name.startsWith("-"))errors3.push('starts with "-"');if(errors3.length>0)throw Error(`Invalid team name '${name}': must be a valid git branch name (${errors3.join(", ")})`)}async function killWorkersByName(agentName,teamName){let matches=(await list()).filter((w)=>(w.role===agentName||w.id===agentName)&&(!teamName||w.team===teamName));for(let w of matches){try{if(w.paneId&&w.paneId!=="inline"){let{execSync:execSync3}=__require("child_process");execSync3(`tmux kill-pane -t ${w.paneId}`,{stdio:"ignore"})}}catch{}await unregister(w.id)}}async function ensureWorktree(repoPath,branchName,worktreePath,baseBranch){try{await $3`git -C ${repoPath} fetch origin ${baseBranch}`.quiet()}catch{}if(await mkdir6(path2.dirname(worktreePath),{recursive:!0}),existsSync14(worktreePath))return;let branchExists=!1;try{await $3`git -C ${repoPath} rev-parse --verify ${branchName}`.quiet(),branchExists=!0}catch{if(!branchExists)try{await $3`git -C ${repoPath} branch ${branchName} origin/${baseBranch}`.quiet()}catch{try{await $3`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet()}catch{await $3`git -C ${repoPath} branch ${branchName}`.quiet()}}}await $3`git clone --shared --branch ${branchName} ${repoPath} ${worktreePath}`.quiet();try{let userName=(await $3`git -C ${repoPath} config user.name`.quiet()).text().trim(),userEmail=(await $3`git -C ${repoPath} config user.email`.quiet()).text().trim();if(userName)await $3`git -C ${worktreePath} config user.name ${userName}`.quiet();if(userEmail)await $3`git -C ${worktreePath} config user.email ${userEmail}`.quiet()}catch{}}async function createTeam(name,repo,baseBranch="dev"){validateBranchName(name);let repoPath=path2.resolve(repo),dir=teamsDir();await mkdir6(dir,{recursive:!0});let filePath=teamFilePath(name);if(existsSync14(filePath)){let content=await readFile5(filePath,"utf-8");return JSON.parse(content)}let worktreeBase=getWorktreeBase(repoPath),worktreePath=join16(worktreeBase,name);await ensureWorktree(repoPath,name,worktreePath,baseBranch);let now=new Date().toISOString(),config={name,repo:repoPath,baseBranch,worktreePath,members:[],status:"in_progress",createdAt:now};if(isInsideClaudeCode()){config.nativeTeamsEnabled=!0;try{let result=await registerAsTeamLead(name);config.nativeTeamParentSessionId=result.sessionId}catch{}}return await writeFile5(filePath,JSON.stringify(config,null,2)),config}async function hireAgent(teamName,agentName){let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);let added;if(agentName==="council")added=BUILTIN_COUNCIL_MEMBERS.map((m)=>m.name).filter((n)=>!config.members.includes(n)),config.members.push(...added);else{if(config.members.includes(agentName))return[];config.members.push(agentName),added=[agentName]}let filePath=teamFilePath(teamName);return await writeFile5(filePath,JSON.stringify(config,null,2)),added}async function fireAgent(teamName,agentName){let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);let idx=config.members.indexOf(agentName);if(idx===-1)return!1;config.members.splice(idx,1);let filePath=teamFilePath(teamName);await writeFile5(filePath,JSON.stringify(config,null,2));try{await killWorkersByName(agentName)}catch{}return!0}async function disbandTeam(teamName){let config=await getTeam2(teamName);if(!config)return!1;try{await deleteNativeTeam(teamName)}catch{}for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}if(config.worktreePath&&existsSync14(config.worktreePath))try{await rm3(config.worktreePath,{recursive:!0,force:!0})}catch{}let filePath=teamFilePath(teamName);try{await unlink4(filePath)}catch{return!1}return await pruneStaleWorktrees(config.repo),!0}async function pruneStaleWorktrees(_repoPath){let dir=teamsDir(),files;try{files=await readdir2(dir)}catch{return}for(let file of files){if(!file.endsWith(".json"))continue;try{let content=await readFile5(join16(dir,file),"utf-8"),config=JSON.parse(content);if(config.worktreePath&&!existsSync14(config.worktreePath)){try{await deleteNativeTeam(config.name)}catch{}await unlink4(join16(dir,file))}}catch{}}}async function updateTeamConfig(name,config){let filePath=teamFilePath(name);await writeFile5(filePath,JSON.stringify(config,null,2))}async function getTeam2(name){try{let content=await readFile5(teamFilePath(name),"utf-8");return JSON.parse(content)}catch{return null}}async function listTeams2(){let dir=teamsDir();try{let files=await readdir2(dir),teams=[];for(let file of files){if(!file.endsWith(".json"))continue;try{let content=await readFile5(join16(dir,file),"utf-8");teams.push(JSON.parse(content))}catch{}}return teams}catch{return[]}}async function listMembers(teamName){let config=await getTeam2(teamName);if(!config)return null;return config.members}async function killTeamMembers(teamName){let config=await getTeam2(teamName);if(!config)return;for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}}async function setTeamStatus(teamName,status){let filePath=teamFilePath(teamName),release=await acquireLock(filePath);try{let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);config.status=status,await writeFile5(filePath,JSON.stringify(config,null,2))}finally{await release()}}var init_team_manager=__esm(()=>{init_agent_registry();init_builtin_agents();init_claude_native_teams();init_file_lock();init_genie_config2()});import{readdirSync as readdirSync4}from"fs";import{join as join17}from"path";function getMigrationsDir(){return join17(import.meta.dir,"..","db","migrations")}async function loadMigrationFiles(){let candidates=[getMigrationsDir(),join17(process.cwd(),"src","db","migrations")];for(let dir of candidates)try{let files=readdirSync4(dir).filter((f)=>f.endsWith(".sql")).sort();if(files.length===0)continue;let migrations=[];for(let file of files){let content=await Bun.file(join17(dir,file)).text();migrations.push({name:file.replace(/\.sql$/,""),sql:content})}return migrations}catch{}return[]}async function ensureMigrationsTable(sql){await sql`
131
+ `).filter(Boolean),messages=[];for(let line of lines)try{messages.push(JSON.parse(line))}catch{}return messages}catch{return[]}}async function markDelivered(repoPath,workerId,messageId){await mkdir5(mailboxDir(repoPath),{recursive:!0});let release=await acquireLock(mailboxFilePath(repoPath,workerId));try{let mailbox=await loadMailbox(repoPath,workerId),msg=mailbox.messages.find((m)=>m.id===messageId);if(!msg)return!1;return msg.deliveredAt=new Date().toISOString(),await saveMailbox(repoPath,mailbox),!0}finally{await release()}}function toNativeInboxMessage(msg,color="blue"){let words=msg.body.split(/\s+/),summary=words.slice(0,8).join(" ")+(words.length>8?"...":"");return{from:msg.from,text:msg.body,summary,timestamp:msg.createdAt,color,read:!1}}var init_mailbox=__esm(()=>{init_esm7();init_file_lock()});import{readdirSync as readdirSync4}from"fs";import{join as join16}from"path";function getMigrationsDir(){return join16(import.meta.dir,"..","db","migrations")}async function loadMigrationFiles(){let candidates=[getMigrationsDir(),join16(process.cwd(),"src","db","migrations")];for(let dir of candidates)try{let files=readdirSync4(dir).filter((f)=>f.endsWith(".sql")).sort();if(files.length===0)continue;let migrations=[];for(let file of files){let content=await Bun.file(join16(dir,file)).text();migrations.push({name:file.replace(/\.sql$/,""),sql:content})}return migrations}catch{}return[]}async function ensureMigrationsTable(sql){await sql`
132
132
  CREATE TABLE IF NOT EXISTS _genie_migrations (
133
133
  id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
134
134
  name TEXT UNIQUE NOT NULL,
@@ -149,7 +149,7 @@ ${errCtx.stack}`;d.reject(err)}else d.resolve(msg)}});return sub.requestSubject=
149
149
  `],[],execute)).forEach(({oid,typarray})=>addArrayType(oid,typarray))}function addArrayType(oid,typarray){if(!!options.parsers[typarray]&&!!options.serializers[typarray])return;let parser=options.parsers[oid];options.shared.typeArrayMap[oid]=typarray,options.parsers[typarray]=(xs)=>arrayParser(xs,parser,typarray),options.parsers[typarray].array=!0,options.serializers[typarray]=(xs)=>arraySerializer(xs,options.serializers[oid],options,typarray)}function tryNext(x,xs){return x==="read-write"&&xs.default_transaction_read_only==="on"||x==="read-only"&&xs.default_transaction_read_only==="off"||x==="primary"&&xs.in_hot_standby==="on"||x==="standby"&&xs.in_hot_standby==="off"||x==="prefer-standby"&&xs.in_hot_standby==="off"&&options.host[retries]}function fetchState(){let query2=new Query([`
150
150
  show transaction_read_only;
151
151
  select pg_catalog.pg_is_in_recovery()
152
- `],[],execute,null,{simple:!0});query2.resolve=([[a],[b2]])=>{backendParameters.default_transaction_read_only=a.transaction_read_only,backendParameters.in_hot_standby=b2.pg_is_in_recovery?"on":"off"},query2.execute()}function ErrorResponse(x){if(query)(query.cursorFn||query.describeFirst)&&write(Sync),errorResponse=Errors.postgres(parseError(x));else errored(Errors.postgres(parseError(x)))}function retry(q,error3){delete statements[q.signature],q.retried=error3,execute(q)}function NotificationResponse(x){if(!onnotify)return;let index=9;while(x[index++]!==0);onnotify(x.toString("utf8",9,index-1),x.toString("utf8",index,x.length-1))}async function PortalSuspended(){try{let x=await Promise.resolve(query.cursorFn(result));rows=0,x===CLOSE?write(Close(query.portal)):(result=new Result,write(Execute("",query.cursorRows)))}catch(err){write(Sync),query.reject(err)}}function CloseComplete(){result.count&&query.cursorFn(result),query.resolve(result)}function CopyInResponse(){stream=new Stream.Writable({autoDestroy:!0,write(chunk2,encoding,callback){socket.write(bytes_default().d().raw(chunk2).end(),callback)},destroy(error3,callback){callback(error3),socket.write(bytes_default().f().str(error3+bytes_default.N).end()),stream=null},final(callback){socket.write(bytes_default().c().end()),final=callback,stream=null}}),query.resolve(stream)}function CopyOutResponse(){stream=new Stream.Readable({read(){socket.resume()}}),query.resolve(stream)}function CopyBothResponse(){stream=new Stream.Duplex({autoDestroy:!0,read(){socket.resume()},write(chunk2,encoding,callback){socket.write(bytes_default().d().raw(chunk2).end(),callback)},destroy(error3,callback){callback(error3),socket.write(bytes_default().f().str(error3+bytes_default.N).end()),stream=null},final(callback){socket.write(bytes_default().c().end()),final=callback}}),query.resolve(stream)}function CopyData(x){stream&&(stream.push(x.subarray(5))||socket.pause())}function CopyDone(){stream&&stream.push(null),stream=null}function NoticeResponse(x){onnotice?onnotice(parseError(x)):console.log(parseError(x))}function EmptyQueryResponse(){}function FunctionCallResponse(){errored(Errors.notSupported("FunctionCallResponse"))}function NegotiateProtocolVersion(){errored(Errors.notSupported("NegotiateProtocolVersion"))}function UnknownMessage(x){console.error("Postgres.js : Unknown Message:",x[0])}function UnknownAuth(x,type2){console.error("Postgres.js : Unknown Auth:",type2)}function Bind(parameters,types3,statement="",portal=""){let prev,type2;return bytes_default().B().str(portal+bytes_default.N).str(statement+bytes_default.N).i16(0).i16(parameters.length),parameters.forEach((x,i2)=>{if(x===null)return bytes_default.i32(4294967295);type2=types3[i2],parameters[i2]=x=type2 in options.serializers?options.serializers[type2](x):""+x,prev=bytes_default.i,bytes_default.inc(4).str(x).i32(bytes_default.i-prev-4,prev)}),bytes_default.i16(0),bytes_default.end()}function Parse(str2,parameters,types3,name=""){return bytes_default().P().str(name+bytes_default.N).str(str2+bytes_default.N).i16(parameters.length),parameters.forEach((x,i2)=>bytes_default.i32(types3[i2]||0)),bytes_default.end()}function Describe(x,name=""){return bytes_default().D().str(x).str(name+bytes_default.N).end()}function Execute(portal="",rows2=0){return Buffer.concat([bytes_default().E().str(portal+bytes_default.N).i32(rows2).end(),Flush])}function Close(portal=""){return Buffer.concat([bytes_default().C().str("P").str(portal+bytes_default.N).end(),bytes_default().S().end()])}function StartupMessage(){return cancelMessage||bytes_default().inc(4).i16(3).z(2).str(Object.entries(Object.assign({user,database,client_encoding:"UTF8"},options.connection)).filter(([,v])=>v).map(([k,v])=>k+bytes_default.N+v).join(bytes_default.N)).z(2).end(0)}}function parseError(x){let error2={},start=5;for(let i2=5;i2<x.length-1;i2++)if(x[i2]===0)error2[errorFields[x[start]]]=x.toString("utf8",start+1,i2),start=i2+1;return error2}function md5(x){return crypto2.createHash("md5").update(x).digest("hex")}function hmac(key,x){return crypto2.createHmac("sha256",key).update(x).digest()}function sha256(x){return crypto2.createHash("sha256").update(x).digest()}function xor(a,b2){let length=Math.max(a.length,b2.length),buffer2=Buffer.allocUnsafe(length);for(let i2=0;i2<length;i2++)buffer2[i2]=a[i2]^b2[i2];return buffer2}function timer(fn,seconds){if(seconds=typeof seconds==="function"?seconds():seconds,!seconds)return{cancel:noop,start:noop};let timer2;return{cancel(){timer2&&(clearTimeout(timer2),timer2=null)},start(){timer2&&clearTimeout(timer2),timer2=setTimeout(done,seconds*1000,arguments)}};function done(args){fn.apply(null,args),timer2=null}}var connection_default,uid=1,Sync,Flush,SSLRequest,ExecuteUnnamed,DescribeUnnamed,noop=()=>{},retryRoutines,errorFields;var init_connection=__esm(()=>{init_types3();init_errors3();init_result();init_queue();init_query();init_bytes();connection_default=Connection,Sync=bytes_default().S().end(),Flush=bytes_default().H().end(),SSLRequest=bytes_default().i32(8).i32(80877103).end(8),ExecuteUnnamed=Buffer.concat([bytes_default().E().str(bytes_default.N).i32(0).end(),Sync]),DescribeUnnamed=bytes_default().D().str("S").str(bytes_default.N).end(),retryRoutines=new Set(["FetchPreparedStatement","RevalidateCachedQuery","transformAssignedExpr"]),errorFields={83:"severity_local",86:"severity",67:"code",77:"message",68:"detail",72:"hint",80:"position",112:"internal_position",113:"internal_query",87:"where",115:"schema_name",116:"table_name",99:"column_name",100:"data type_name",110:"constraint_name",70:"file",76:"line",82:"routine"}});function Subscribe(postgres2,options){let subscribers=new Map,slot="postgresjs_"+Math.random().toString(36).slice(2),state2={},connection2,stream,ended=!1,sql=subscribe2.sql=postgres2({...options,transform:{column:{},value:{},row:{}},max:1,fetch_types:!1,idle_timeout:null,max_lifetime:null,connection:{...options.connection,replication:"database"},onclose:async function(){if(ended)return;stream=null,state2.pid=state2.secret=void 0,connected(await init(sql,slot,options.publications)),subscribers.forEach((event)=>event.forEach(({onsubscribe})=>onsubscribe()))},no_subscribe:!0}),end=sql.end,close2=sql.close;return sql.end=async()=>{return ended=!0,stream&&await new Promise((r)=>(stream.once("close",r),stream.end())),end()},sql.close=async()=>{return stream&&await new Promise((r)=>(stream.once("close",r),stream.end())),close2()},subscribe2;async function subscribe2(event,fn,onsubscribe=noop2,onerror=noop2){if(event=parseEvent(event),!connection2)connection2=init(sql,slot,options.publications);let subscriber={fn,onsubscribe},fns=subscribers.has(event)?subscribers.get(event).add(subscriber):subscribers.set(event,new Set([subscriber])).get(event),unsubscribe=()=>{fns.delete(subscriber),fns.size===0&&subscribers.delete(event)};return connection2.then((x)=>{return connected(x),onsubscribe(),stream&&stream.on("error",onerror),{unsubscribe,state:state2,sql}})}function connected(x){stream=x.stream,state2.pid=x.state.pid,state2.secret=x.state.secret}async function init(sql2,slot2,publications){if(!publications)throw Error("Missing publication names");let xs=await sql2.unsafe(`CREATE_REPLICATION_SLOT ${slot2} TEMPORARY LOGICAL pgoutput NOEXPORT_SNAPSHOT`),[x]=xs,stream2=await sql2.unsafe(`START_REPLICATION SLOT ${slot2} LOGICAL ${x.consistent_point} (proto_version '1', publication_names '${publications}')`).writable(),state3={lsn:Buffer.concat(x.consistent_point.split("/").map((x2)=>Buffer.from(("00000000"+x2).slice(-8),"hex")))};return stream2.on("data",data),stream2.on("error",error2),stream2.on("close",sql2.close),{stream:stream2,state:xs.state};function error2(e){console.error("Unexpected error during logical streaming - reconnecting",e)}function data(x2){if(x2[0]===119)parse(x2.subarray(25),state3,sql2.options.parsers,handle,options.transform);else if(x2[0]===107&&x2[17])state3.lsn=x2.subarray(1,9),pong()}function handle(a,b2){let path3=b2.relation.schema+"."+b2.relation.table;call("*",a,b2),call("*:"+path3,a,b2),b2.relation.keys.length&&call("*:"+path3+"="+b2.relation.keys.map((x2)=>a[x2.name]),a,b2),call(b2.command,a,b2),call(b2.command+":"+path3,a,b2),b2.relation.keys.length&&call(b2.command+":"+path3+"="+b2.relation.keys.map((x2)=>a[x2.name]),a,b2)}function pong(){let x2=Buffer.alloc(34);x2[0]=114,x2.fill(state3.lsn,1),x2.writeBigInt64BE(BigInt(Date.now()-Date.UTC(2000,0,1))*BigInt(1000),25),stream2.write(x2)}}function call(x,a,b2){subscribers.has(x)&&subscribers.get(x).forEach(({fn})=>fn(a,b2,x))}}function Time(x){return new Date(Date.UTC(2000,0,1)+Number(x/BigInt(1000)))}function parse(x,state2,parsers2,handle,transform){let char=(acc,[k,v])=>(acc[k.charCodeAt(0)]=v,acc);Object.entries({R:(x2)=>{let i2=1,r=state2[x2.readUInt32BE(i2)]={schema:x2.toString("utf8",i2+=4,i2=x2.indexOf(0,i2))||"pg_catalog",table:x2.toString("utf8",i2+1,i2=x2.indexOf(0,i2+1)),columns:Array(x2.readUInt16BE(i2+=2)),keys:[]};i2+=2;let columnIndex=0,column;while(i2<x2.length)column=r.columns[columnIndex++]={key:x2[i2++],name:transform.column.from?transform.column.from(x2.toString("utf8",i2,i2=x2.indexOf(0,i2))):x2.toString("utf8",i2,i2=x2.indexOf(0,i2)),type:x2.readUInt32BE(i2+=1),parser:parsers2[x2.readUInt32BE(i2)],atttypmod:x2.readUInt32BE(i2+=4)},column.key&&r.keys.push(column),i2+=4},Y:()=>{},O:()=>{},B:(x2)=>{state2.date=Time(x2.readBigInt64BE(9)),state2.lsn=x2.subarray(1,9)},I:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)],{row}=tuples(x2,relation.columns,i2+=7,transform);handle(row,{command:"insert",relation})},D:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)];i2+=4;let key=x2[i2]===75;handle(key||x2[i2]===79?tuples(x2,relation.columns,i2+=3,transform).row:null,{command:"delete",relation,key})},U:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)];i2+=4;let key=x2[i2]===75,xs=key||x2[i2]===79?tuples(x2,relation.columns,i2+=3,transform):null;xs&&(i2=xs.i);let{row}=tuples(x2,relation.columns,i2+3,transform);handle(row,{command:"update",relation,key,old:xs&&xs.row})},T:()=>{},C:()=>{}}).reduce(char,{})[x[0]](x)}function tuples(x,columns,xi,transform){let type2,column,value,row=transform.raw?Array(columns.length):{};for(let i2=0;i2<columns.length;i2++)type2=x[xi++],column=columns[i2],value=type2===110?null:type2===117?void 0:column.parser===void 0?x.toString("utf8",xi+4,xi+=4+x.readUInt32BE(xi)):column.parser.array===!0?column.parser(x.toString("utf8",xi+5,xi+=4+x.readUInt32BE(xi))):column.parser(x.toString("utf8",xi+4,xi+=4+x.readUInt32BE(xi))),transform.raw?row[i2]=transform.raw===!0?value:transform.value.from?transform.value.from(value,column):value:row[column.name]=transform.value.from?transform.value.from(value,column):value;return{i:xi,row:transform.row.from?transform.row.from(row):row}}function parseEvent(x){let xs=x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i)||[];if(!xs)throw Error("Malformed subscribe pattern: "+x);let[,command,path3,key]=xs;return(command||"*")+(path3?":"+(path3.indexOf(".")===-1?"public."+path3:path3):"")+(key?"="+key:"")}var noop2=()=>{};import Stream2 from"stream";function largeObject(sql,oid,mode=393216){return new Promise(async(resolve4,reject)=>{await sql.begin(async(sql2)=>{let finish;!oid&&([{oid}]=await sql2`select lo_creat(-1) as oid`);let[{fd}]=await sql2`select lo_open(${oid}, ${mode}) as fd`,lo={writable,readable,close:()=>sql2`select lo_close(${fd})`.then(finish),tell:()=>sql2`select lo_tell64(${fd})`,read:(x)=>sql2`select loread(${fd}, ${x}) as data`,write:(x)=>sql2`select lowrite(${fd}, ${x})`,truncate:(x)=>sql2`select lo_truncate64(${fd}, ${x})`,seek:(x,whence=0)=>sql2`select lo_lseek64(${fd}, ${x}, ${whence})`,size:()=>sql2`
152
+ `],[],execute,null,{simple:!0});query2.resolve=([[a],[b2]])=>{backendParameters.default_transaction_read_only=a.transaction_read_only,backendParameters.in_hot_standby=b2.pg_is_in_recovery?"on":"off"},query2.execute()}function ErrorResponse(x){if(query)(query.cursorFn||query.describeFirst)&&write(Sync),errorResponse=Errors.postgres(parseError(x));else errored(Errors.postgres(parseError(x)))}function retry(q,error3){delete statements[q.signature],q.retried=error3,execute(q)}function NotificationResponse(x){if(!onnotify)return;let index=9;while(x[index++]!==0);onnotify(x.toString("utf8",9,index-1),x.toString("utf8",index,x.length-1))}async function PortalSuspended(){try{let x=await Promise.resolve(query.cursorFn(result));rows=0,x===CLOSE?write(Close(query.portal)):(result=new Result,write(Execute("",query.cursorRows)))}catch(err){write(Sync),query.reject(err)}}function CloseComplete(){result.count&&query.cursorFn(result),query.resolve(result)}function CopyInResponse(){stream=new Stream.Writable({autoDestroy:!0,write(chunk2,encoding,callback){socket.write(bytes_default().d().raw(chunk2).end(),callback)},destroy(error3,callback){callback(error3),socket.write(bytes_default().f().str(error3+bytes_default.N).end()),stream=null},final(callback){socket.write(bytes_default().c().end()),final=callback,stream=null}}),query.resolve(stream)}function CopyOutResponse(){stream=new Stream.Readable({read(){socket.resume()}}),query.resolve(stream)}function CopyBothResponse(){stream=new Stream.Duplex({autoDestroy:!0,read(){socket.resume()},write(chunk2,encoding,callback){socket.write(bytes_default().d().raw(chunk2).end(),callback)},destroy(error3,callback){callback(error3),socket.write(bytes_default().f().str(error3+bytes_default.N).end()),stream=null},final(callback){socket.write(bytes_default().c().end()),final=callback}}),query.resolve(stream)}function CopyData(x){stream&&(stream.push(x.subarray(5))||socket.pause())}function CopyDone(){stream&&stream.push(null),stream=null}function NoticeResponse(x){onnotice?onnotice(parseError(x)):console.log(parseError(x))}function EmptyQueryResponse(){}function FunctionCallResponse(){errored(Errors.notSupported("FunctionCallResponse"))}function NegotiateProtocolVersion(){errored(Errors.notSupported("NegotiateProtocolVersion"))}function UnknownMessage(x){console.error("Postgres.js : Unknown Message:",x[0])}function UnknownAuth(x,type2){console.error("Postgres.js : Unknown Auth:",type2)}function Bind(parameters,types3,statement="",portal=""){let prev,type2;return bytes_default().B().str(portal+bytes_default.N).str(statement+bytes_default.N).i16(0).i16(parameters.length),parameters.forEach((x,i2)=>{if(x===null)return bytes_default.i32(4294967295);type2=types3[i2],parameters[i2]=x=type2 in options.serializers?options.serializers[type2](x):""+x,prev=bytes_default.i,bytes_default.inc(4).str(x).i32(bytes_default.i-prev-4,prev)}),bytes_default.i16(0),bytes_default.end()}function Parse(str2,parameters,types3,name=""){return bytes_default().P().str(name+bytes_default.N).str(str2+bytes_default.N).i16(parameters.length),parameters.forEach((x,i2)=>bytes_default.i32(types3[i2]||0)),bytes_default.end()}function Describe(x,name=""){return bytes_default().D().str(x).str(name+bytes_default.N).end()}function Execute(portal="",rows2=0){return Buffer.concat([bytes_default().E().str(portal+bytes_default.N).i32(rows2).end(),Flush])}function Close(portal=""){return Buffer.concat([bytes_default().C().str("P").str(portal+bytes_default.N).end(),bytes_default().S().end()])}function StartupMessage(){return cancelMessage||bytes_default().inc(4).i16(3).z(2).str(Object.entries(Object.assign({user,database,client_encoding:"UTF8"},options.connection)).filter(([,v])=>v).map(([k,v])=>k+bytes_default.N+v).join(bytes_default.N)).z(2).end(0)}}function parseError(x){let error2={},start=5;for(let i2=5;i2<x.length-1;i2++)if(x[i2]===0)error2[errorFields[x[start]]]=x.toString("utf8",start+1,i2),start=i2+1;return error2}function md5(x){return crypto2.createHash("md5").update(x).digest("hex")}function hmac(key,x){return crypto2.createHmac("sha256",key).update(x).digest()}function sha256(x){return crypto2.createHash("sha256").update(x).digest()}function xor(a,b2){let length=Math.max(a.length,b2.length),buffer2=Buffer.allocUnsafe(length);for(let i2=0;i2<length;i2++)buffer2[i2]=a[i2]^b2[i2];return buffer2}function timer(fn,seconds){if(seconds=typeof seconds==="function"?seconds():seconds,!seconds)return{cancel:noop,start:noop};let timer2;return{cancel(){timer2&&(clearTimeout(timer2),timer2=null)},start(){timer2&&clearTimeout(timer2),timer2=setTimeout(done,seconds*1000,arguments)}};function done(args){fn.apply(null,args),timer2=null}}var connection_default,uid=1,Sync,Flush,SSLRequest,ExecuteUnnamed,DescribeUnnamed,noop=()=>{},retryRoutines,errorFields;var init_connection=__esm(()=>{init_types3();init_errors3();init_result();init_queue();init_query();init_bytes();connection_default=Connection,Sync=bytes_default().S().end(),Flush=bytes_default().H().end(),SSLRequest=bytes_default().i32(8).i32(80877103).end(8),ExecuteUnnamed=Buffer.concat([bytes_default().E().str(bytes_default.N).i32(0).end(),Sync]),DescribeUnnamed=bytes_default().D().str("S").str(bytes_default.N).end(),retryRoutines=new Set(["FetchPreparedStatement","RevalidateCachedQuery","transformAssignedExpr"]),errorFields={83:"severity_local",86:"severity",67:"code",77:"message",68:"detail",72:"hint",80:"position",112:"internal_position",113:"internal_query",87:"where",115:"schema_name",116:"table_name",99:"column_name",100:"data type_name",110:"constraint_name",70:"file",76:"line",82:"routine"}});function Subscribe(postgres2,options){let subscribers=new Map,slot="postgresjs_"+Math.random().toString(36).slice(2),state2={},connection2,stream,ended=!1,sql=subscribe2.sql=postgres2({...options,transform:{column:{},value:{},row:{}},max:1,fetch_types:!1,idle_timeout:null,max_lifetime:null,connection:{...options.connection,replication:"database"},onclose:async function(){if(ended)return;stream=null,state2.pid=state2.secret=void 0,connected(await init(sql,slot,options.publications)),subscribers.forEach((event)=>event.forEach(({onsubscribe})=>onsubscribe()))},no_subscribe:!0}),end=sql.end,close2=sql.close;return sql.end=async()=>{return ended=!0,stream&&await new Promise((r)=>(stream.once("close",r),stream.end())),end()},sql.close=async()=>{return stream&&await new Promise((r)=>(stream.once("close",r),stream.end())),close2()},subscribe2;async function subscribe2(event,fn,onsubscribe=noop2,onerror=noop2){if(event=parseEvent(event),!connection2)connection2=init(sql,slot,options.publications);let subscriber={fn,onsubscribe},fns=subscribers.has(event)?subscribers.get(event).add(subscriber):subscribers.set(event,new Set([subscriber])).get(event),unsubscribe=()=>{fns.delete(subscriber),fns.size===0&&subscribers.delete(event)};return connection2.then((x)=>{return connected(x),onsubscribe(),stream&&stream.on("error",onerror),{unsubscribe,state:state2,sql}})}function connected(x){stream=x.stream,state2.pid=x.state.pid,state2.secret=x.state.secret}async function init(sql2,slot2,publications){if(!publications)throw Error("Missing publication names");let xs=await sql2.unsafe(`CREATE_REPLICATION_SLOT ${slot2} TEMPORARY LOGICAL pgoutput NOEXPORT_SNAPSHOT`),[x]=xs,stream2=await sql2.unsafe(`START_REPLICATION SLOT ${slot2} LOGICAL ${x.consistent_point} (proto_version '1', publication_names '${publications}')`).writable(),state3={lsn:Buffer.concat(x.consistent_point.split("/").map((x2)=>Buffer.from(("00000000"+x2).slice(-8),"hex")))};return stream2.on("data",data),stream2.on("error",error2),stream2.on("close",sql2.close),{stream:stream2,state:xs.state};function error2(e){console.error("Unexpected error during logical streaming - reconnecting",e)}function data(x2){if(x2[0]===119)parse(x2.subarray(25),state3,sql2.options.parsers,handle,options.transform);else if(x2[0]===107&&x2[17])state3.lsn=x2.subarray(1,9),pong()}function handle(a,b2){let path2=b2.relation.schema+"."+b2.relation.table;call("*",a,b2),call("*:"+path2,a,b2),b2.relation.keys.length&&call("*:"+path2+"="+b2.relation.keys.map((x2)=>a[x2.name]),a,b2),call(b2.command,a,b2),call(b2.command+":"+path2,a,b2),b2.relation.keys.length&&call(b2.command+":"+path2+"="+b2.relation.keys.map((x2)=>a[x2.name]),a,b2)}function pong(){let x2=Buffer.alloc(34);x2[0]=114,x2.fill(state3.lsn,1),x2.writeBigInt64BE(BigInt(Date.now()-Date.UTC(2000,0,1))*BigInt(1000),25),stream2.write(x2)}}function call(x,a,b2){subscribers.has(x)&&subscribers.get(x).forEach(({fn})=>fn(a,b2,x))}}function Time(x){return new Date(Date.UTC(2000,0,1)+Number(x/BigInt(1000)))}function parse(x,state2,parsers2,handle,transform){let char=(acc,[k,v])=>(acc[k.charCodeAt(0)]=v,acc);Object.entries({R:(x2)=>{let i2=1,r=state2[x2.readUInt32BE(i2)]={schema:x2.toString("utf8",i2+=4,i2=x2.indexOf(0,i2))||"pg_catalog",table:x2.toString("utf8",i2+1,i2=x2.indexOf(0,i2+1)),columns:Array(x2.readUInt16BE(i2+=2)),keys:[]};i2+=2;let columnIndex=0,column;while(i2<x2.length)column=r.columns[columnIndex++]={key:x2[i2++],name:transform.column.from?transform.column.from(x2.toString("utf8",i2,i2=x2.indexOf(0,i2))):x2.toString("utf8",i2,i2=x2.indexOf(0,i2)),type:x2.readUInt32BE(i2+=1),parser:parsers2[x2.readUInt32BE(i2)],atttypmod:x2.readUInt32BE(i2+=4)},column.key&&r.keys.push(column),i2+=4},Y:()=>{},O:()=>{},B:(x2)=>{state2.date=Time(x2.readBigInt64BE(9)),state2.lsn=x2.subarray(1,9)},I:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)],{row}=tuples(x2,relation.columns,i2+=7,transform);handle(row,{command:"insert",relation})},D:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)];i2+=4;let key=x2[i2]===75;handle(key||x2[i2]===79?tuples(x2,relation.columns,i2+=3,transform).row:null,{command:"delete",relation,key})},U:(x2)=>{let i2=1,relation=state2[x2.readUInt32BE(i2)];i2+=4;let key=x2[i2]===75,xs=key||x2[i2]===79?tuples(x2,relation.columns,i2+=3,transform):null;xs&&(i2=xs.i);let{row}=tuples(x2,relation.columns,i2+3,transform);handle(row,{command:"update",relation,key,old:xs&&xs.row})},T:()=>{},C:()=>{}}).reduce(char,{})[x[0]](x)}function tuples(x,columns,xi,transform){let type2,column,value,row=transform.raw?Array(columns.length):{};for(let i2=0;i2<columns.length;i2++)type2=x[xi++],column=columns[i2],value=type2===110?null:type2===117?void 0:column.parser===void 0?x.toString("utf8",xi+4,xi+=4+x.readUInt32BE(xi)):column.parser.array===!0?column.parser(x.toString("utf8",xi+5,xi+=4+x.readUInt32BE(xi))):column.parser(x.toString("utf8",xi+4,xi+=4+x.readUInt32BE(xi))),transform.raw?row[i2]=transform.raw===!0?value:transform.value.from?transform.value.from(value,column):value:row[column.name]=transform.value.from?transform.value.from(value,column):value;return{i:xi,row:transform.row.from?transform.row.from(row):row}}function parseEvent(x){let xs=x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i)||[];if(!xs)throw Error("Malformed subscribe pattern: "+x);let[,command,path2,key]=xs;return(command||"*")+(path2?":"+(path2.indexOf(".")===-1?"public."+path2:path2):"")+(key?"="+key:"")}var noop2=()=>{};import Stream2 from"stream";function largeObject(sql,oid,mode=393216){return new Promise(async(resolve4,reject)=>{await sql.begin(async(sql2)=>{let finish;!oid&&([{oid}]=await sql2`select lo_creat(-1) as oid`);let[{fd}]=await sql2`select lo_open(${oid}, ${mode}) as fd`,lo={writable,readable,close:()=>sql2`select lo_close(${fd})`.then(finish),tell:()=>sql2`select lo_tell64(${fd})`,read:(x)=>sql2`select loread(${fd}, ${x}) as data`,write:(x)=>sql2`select lowrite(${fd}, ${x})`,truncate:(x)=>sql2`select lo_truncate64(${fd}, ${x})`,seek:(x,whence=0)=>sql2`select lo_lseek64(${fd}, ${x}, ${whence})`,size:()=>sql2`
153
153
  select
154
154
  lo_lseek64(${fd}, location, 0) as position,
155
155
  seek.size
@@ -159,8 +159,8 @@ ${errCtx.stack}`;d.reject(err)}else d.resolve(msg)}});return sub.requestSubject=
159
159
  tell.location
160
160
  from (select lo_tell64($1) as location) tell
161
161
  ) seek
162
- `};return resolve4(lo),new Promise(async(r)=>finish=r);async function readable({highWaterMark=16384,start=0,end=1/0}={}){let max=end-start;return start&&await lo.seek(start),new Stream2.Readable({highWaterMark,async read(size){let l=size>max?size-max:size;max-=size;let[{data}]=await lo.read(l);if(this.push(data),data.length<size)this.push(null)}})}async function writable({highWaterMark=16384,start=0}={}){return start&&await lo.seek(start),new Stream2.Writable({highWaterMark,write(chunk,encoding,callback){lo.write(chunk).then(()=>callback(),callback)}})}}).catch(reject)})}var init_large=()=>{};var exports_src={};__export(exports_src,{default:()=>src_default});import os from"os";import fs from"fs";function Postgres(a,b2){let options=parseOptions(a,b2),subscribe2=options.no_subscribe||Subscribe(Postgres,{...options}),ending=!1,queries=queue_default(),connecting=queue_default(),reserved=queue_default(),closed=queue_default(),ended=queue_default(),open2=queue_default(),busy=queue_default(),full=queue_default(),queues={connecting,reserved,closed,ended,open:open2,busy,full},connections=[...Array(options.max)].map(()=>connection_default(options,queues,{onopen,onend,onclose})),sql=Sql(handler);return Object.assign(sql,{get parameters(){return options.parameters},largeObject:largeObject.bind(null,sql),subscribe:subscribe2,CLOSE,END:CLOSE,PostgresError,options,reserve,listen,begin,close:close2,end}),sql;function Sql(handler2){return handler2.debug=options.debug,Object.entries(options.types).reduce((acc,[name,type2])=>{return acc[name]=(x)=>new Parameter(x,type2.to),acc},typed),Object.assign(sql2,{types:typed,typed,unsafe,notify,array,json:json2,file}),sql2;function typed(value,type2){return new Parameter(value,type2)}function sql2(strings,...args){return strings&&Array.isArray(strings.raw)?new Query(strings,args,handler2,cancel):typeof strings==="string"&&!args.length?new Identifier(options.transform.column.to?options.transform.column.to(strings):strings):new Builder(strings,args)}function unsafe(string,args=[],options2={}){return arguments.length===2&&!Array.isArray(args)&&(options2=args,args=[]),new Query([string],args,handler2,cancel,{prepare:!1,...options2,simple:"simple"in options2?options2.simple:args.length===0})}function file(path3,args=[],options2={}){return arguments.length===2&&!Array.isArray(args)&&(options2=args,args=[]),new Query([],args,(query2)=>{fs.readFile(path3,"utf8",(err,string)=>{if(err)return query2.reject(err);query2.strings=[string],handler2(query2)})},cancel,{...options2,simple:"simple"in options2?options2.simple:args.length===0})}}async function listen(name,fn,onlisten){let listener={fn,onlisten},sql2=listen.sql||(listen.sql=Postgres({...options,max:1,idle_timeout:null,max_lifetime:null,fetch_types:!1,onclose(){Object.entries(listen.channels).forEach(([name2,{listeners}])=>{delete listen.channels[name2],Promise.all(listeners.map((l)=>listen(name2,l.fn,l.onlisten).catch(()=>{})))})},onnotify(c,x){c in listen.channels&&listen.channels[c].listeners.forEach((l)=>l.fn(x))}})),channels=listen.channels||(listen.channels={});if(name in channels){channels[name].listeners.push(listener);let result2=await channels[name].result;return listener.onlisten&&listener.onlisten(),{state:result2.state,unlisten}}channels[name]={result:sql2`listen ${sql2.unsafe('"'+name.replace(/"/g,'""')+'"')}`,listeners:[listener]};let result=await channels[name].result;return listener.onlisten&&listener.onlisten(),{state:result.state,unlisten};async function unlisten(){if(name in channels===!1)return;if(channels[name].listeners=channels[name].listeners.filter((x)=>x!==listener),channels[name].listeners.length)return;return delete channels[name],sql2`unlisten ${sql2.unsafe('"'+name.replace(/"/g,'""')+'"')}`}}async function notify(channel,payload){return await sql`select pg_notify(${channel}, ${""+payload})`}async function reserve(){let queue=queue_default(),c=open2.length?open2.shift():await new Promise((resolve4,reject)=>{let query={reserve:resolve4,reject};queries.push(query),closed.length&&connect(closed.shift(),query)});move(c,reserved),c.reserved=()=>queue.length?c.execute(queue.shift()):move(c,reserved),c.reserved.release=!0;let sql2=Sql(handler2);return sql2.release=()=>{c.reserved=null,onopen(c)},sql2;function handler2(q){c.queue===full?queue.push(q):c.execute(q)||move(c,full)}}async function begin(options2,fn){!fn&&(fn=options2,options2="");let queries2=queue_default(),savepoints=0,connection2,prepare=null;try{return await sql.unsafe("begin "+options2.replace(/[^a-z ]/ig,""),[],{onexecute}).execute(),await Promise.race([scope(connection2,fn),new Promise((_,reject)=>connection2.onclose=reject)])}catch(error2){throw error2}async function scope(c,fn2,name){let sql2=Sql(handler2);sql2.savepoint=savepoint,sql2.prepare=(x)=>prepare=x.replace(/[^a-z0-9$-_. ]/gi);let uncaughtError,result;name&&await sql2`savepoint ${sql2(name)}`;try{if(result=await new Promise((resolve4,reject)=>{let x=fn2(sql2);Promise.resolve(Array.isArray(x)?Promise.all(x):x).then(resolve4,reject)}),uncaughtError)throw uncaughtError}catch(e){throw await(name?sql2`rollback to ${sql2(name)}`:sql2`rollback`),e instanceof PostgresError&&e.code==="25P02"&&uncaughtError||e}if(!name)prepare?await sql2`prepare transaction '${sql2.unsafe(prepare)}'`:await sql2`commit`;return result;function savepoint(name2,fn3){if(name2&&Array.isArray(name2.raw))return savepoint((sql3)=>sql3.apply(sql3,arguments));return arguments.length===1&&(fn3=name2,name2=null),scope(c,fn3,"s"+savepoints+++(name2?"_"+name2:""))}function handler2(q){q.catch((e)=>uncaughtError||(uncaughtError=e)),c.queue===full?queries2.push(q):c.execute(q)||move(c,full)}}function onexecute(c){connection2=c,move(c,reserved),c.reserved=()=>queries2.length?c.execute(queries2.shift()):move(c,reserved)}}function move(c,queue){return c.queue.remove(c),queue.push(c),c.queue=queue,queue===open2?c.idleTimer.start():c.idleTimer.cancel(),c}function json2(x){return new Parameter(x,3802)}function array(x,type2){if(!Array.isArray(x))return array(Array.from(arguments));return new Parameter(x,type2||(x.length?inferType(x)||25:0),options.shared.typeArrayMap)}function handler(query){if(ending)return query.reject(Errors.connection("CONNECTION_ENDED",options,options));if(open2.length)return go(open2.shift(),query);if(closed.length)return connect(closed.shift(),query);busy.length?go(busy.shift(),query):queries.push(query)}function go(c,query){return c.execute(query)?move(c,busy):move(c,full)}function cancel(query){return new Promise((resolve4,reject)=>{query.state?query.active?connection_default(options).cancel(query.state,resolve4,reject):query.cancelled={resolve:resolve4,reject}:(queries.remove(query),query.cancelled=!0,query.reject(Errors.generic("57014","canceling statement due to user request")),resolve4())})}async function end({timeout=null}={}){if(ending)return ending;await 1;let timer2;return ending=Promise.race([new Promise((r)=>timeout!==null&&(timer2=setTimeout(destroy,timeout*1000,r))),Promise.all(connections.map((c)=>c.end()).concat(listen.sql?listen.sql.end({timeout:0}):[],subscribe2.sql?subscribe2.sql.end({timeout:0}):[]))]).then(()=>clearTimeout(timer2))}async function close2(){await Promise.all(connections.map((c)=>c.end()))}async function destroy(resolve4){await Promise.all(connections.map((c)=>c.terminate()));while(queries.length)queries.shift().reject(Errors.connection("CONNECTION_DESTROYED",options));resolve4()}function connect(c,query){return move(c,connecting),c.connect(query),c}function onend(c){move(c,ended)}function onopen(c){if(queries.length===0)return move(c,open2);let max=Math.ceil(queries.length/(connecting.length+1)),ready=!0;while(ready&&queries.length&&max-- >0){let query=queries.shift();if(query.reserve)return query.reserve(c);ready=c.execute(query)}ready?move(c,busy):move(c,full)}function onclose(c,e){move(c,closed),c.reserved=null,c.onclose&&(c.onclose(e),c.onclose=null),options.onclose&&options.onclose(c.id),queries.length&&connect(c,queries.shift())}}function parseOptions(a,b2){if(a&&a.shared)return a;let env=process.env,o=(!a||typeof a==="string"?b2:a)||{},{url,multihost}=parseUrl(a),query=[...url.searchParams].reduce((a2,[b3,c])=>(a2[b3]=c,a2),{}),host=o.hostname||o.host||multihost||url.hostname||env.PGHOST||"localhost",port=o.port||url.port||env.PGPORT||5432,user=o.user||o.username||url.username||env.PGUSERNAME||env.PGUSER||osUsername();o.no_prepare&&(o.prepare=!1),query.sslmode&&(query.ssl=query.sslmode,delete query.sslmode),"timeout"in o&&(console.log("The timeout option is deprecated, use idle_timeout instead"),o.idle_timeout=o.timeout),query.sslrootcert==="system"&&(query.ssl="verify-full");let ints=["idle_timeout","connect_timeout","max_lifetime","max_pipeline","backoff","keep_alive"],defaults={max:globalThis.Cloudflare?3:10,ssl:!1,sslnegotiation:null,idle_timeout:null,connect_timeout:30,max_lifetime,max_pipeline:100,backoff,keep_alive:60,prepare:!0,debug:!1,fetch_types:!0,publications:"alltables",target_session_attrs:null};return{host:Array.isArray(host)?host:host.split(",").map((x)=>x.split(":")[0]),port:Array.isArray(port)?port:host.split(",").map((x)=>parseInt(x.split(":")[1]||port)),path:o.path||host.indexOf("/")>-1&&host+"/.s.PGSQL."+port,database:o.database||o.db||(url.pathname||"").slice(1)||env.PGDATABASE||user,user,pass:o.pass||o.password||url.password||env.PGPASSWORD||"",...Object.entries(defaults).reduce((acc,[k,d])=>{let value=k in o?o[k]:(k in query)?query[k]==="disable"||query[k]==="false"?!1:query[k]:env["PG"+k.toUpperCase()]||d;return acc[k]=typeof value==="string"&&ints.includes(k)?+value:value,acc},{}),connection:{application_name:env.PGAPPNAME||"postgres.js",...o.connection,...Object.entries(query).reduce((acc,[k,v])=>((k in defaults)||(acc[k]=v),acc),{})},types:o.types||{},target_session_attrs:tsa(o,url,env),onnotice:o.onnotice,onnotify:o.onnotify,onclose:o.onclose,onparameter:o.onparameter,socket:o.socket,transform:parseTransform(o.transform||{undefined:void 0}),parameters:{},shared:{retries:0,typeArrayMap:{}},...mergeUserTypes(o.types)}}function tsa(o,url,env){let x=o.target_session_attrs||url.searchParams.get("target_session_attrs")||env.PGTARGETSESSIONATTRS;if(!x||["read-write","read-only","primary","standby","prefer-standby"].includes(x))return x;throw Error("target_session_attrs "+x+" is not supported")}function backoff(retries){return(0.5+Math.random()/2)*Math.min(3**retries/100,20)}function max_lifetime(){return 60*(30+Math.random()*30)}function parseTransform(x){return{undefined:x.undefined,column:{from:typeof x.column==="function"?x.column:x.column&&x.column.from,to:x.column&&x.column.to},value:{from:typeof x.value==="function"?x.value:x.value&&x.value.from,to:x.value&&x.value.to},row:{from:typeof x.row==="function"?x.row:x.row&&x.row.from,to:x.row&&x.row.to}}}function parseUrl(url){if(!url||typeof url!=="string")return{url:{searchParams:new Map}};let host=url;host=host.slice(host.indexOf("://")+3).split(/[?/]/)[0],host=decodeURIComponent(host.slice(host.indexOf("@")+1));let urlObj=new URL(url.replace(host,host.split(",")[0]));return{url:{username:decodeURIComponent(urlObj.username),password:decodeURIComponent(urlObj.password),host:urlObj.host,hostname:urlObj.hostname,port:urlObj.port,pathname:urlObj.pathname,searchParams:urlObj.searchParams},multihost:host.indexOf(",")>-1&&host}}function osUsername(){try{return os.userInfo().username}catch(_){return process.env.USERNAME||process.env.USER||process.env.LOGNAME}}var src_default;var init_src=__esm(()=>{init_types3();init_connection();init_query();init_queue();init_errors3();init_large();Object.assign(Postgres,{PostgresError,toPascal,pascal,toCamel,camel,toKebab,kebab,fromPascal,fromCamel,fromKebab,BigInt:{to:20,from:[20],parse:(x)=>BigInt(x),serialize:(x)=>x.toString()}});src_default=Postgres});var exports_db={};__export(exports_db,{shutdown:()=>shutdown,isAvailable:()=>isAvailable2,getLockfilePath:()=>getLockfilePath,getDataDir:()=>getDataDir,getConnection:()=>getConnection,getActivePort:()=>getActivePort,ensurePgserve:()=>ensurePgserve});import{execSync as execSync3}from"child_process";import{existsSync as existsSync15,mkdirSync as mkdirSync6,readFileSync as readFileSync8,renameSync,unlinkSync as unlinkSync3,writeFileSync as writeFileSync5}from"fs";import{createConnection}from"net";import{homedir as homedir14}from"os";import{join as join18}from"path";function maskCredentials(url){return url.replace(/\/\/.*@/,"//***@")}function killOrphanedPostgres(dataDir){let pidFile=join18(dataDir,"postmaster.pid");if(!existsSync15(pidFile))return;try{let content=readFileSync8(pidFile,"utf-8"),pid=Number.parseInt(content.split(`
163
- `)[0],10);if(Number.isNaN(pid)||pid<=0)return;let cmdline;try{cmdline=execSync3(`ps -o command= -p ${pid} 2>/dev/null`,{encoding:"utf-8"}).trim()}catch{return}if(!cmdline.includes("postgres"))return;try{process.kill(pid,"SIGTERM")}catch{return}let deadline=Date.now()+5000;while(Date.now()<deadline)try{process.kill(pid,0),execSync3("sleep 0.2",{stdio:"ignore"})}catch{return}try{process.kill(pid,"SIGKILL")}catch{}}catch{}}function getPort(){let envPort=process.env.GENIE_PG_PORT;if(envPort){let parsed=Number.parseInt(envPort,10);if(!Number.isNaN(parsed)&&parsed>0&&parsed<65536)return parsed}return DEFAULT_PORT}function isPortListening(port,host){return new Promise((resolve4)=>{let socket=createConnection({port,host},()=>{socket.destroy(),resolve4(!0)});socket.on("error",()=>{socket.destroy(),resolve4(!1)}),socket.setTimeout(1000,()=>{socket.destroy(),resolve4(!1)})})}function readLockfile(){try{let content=readFileSync8(LOCKFILE_PATH,"utf-8").trim(),port=Number.parseInt(content,10);if(!Number.isNaN(port)&&port>0&&port<65536)return port}catch{}return null}function writeLockfile(port){try{mkdirSync6(GENIE_HOME2,{recursive:!0});let tmpPath=`${LOCKFILE_PATH}.tmp.${process.pid}`;writeFileSync5(tmpPath,String(port),"utf-8"),renameSync(tmpPath,LOCKFILE_PATH)}catch{}}function removeLockfile(){try{unlinkSync3(LOCKFILE_PATH)}catch{}}async function ensurePgserve(){if(ensurePromise)return ensurePromise;ensurePromise=_ensurePgserve();try{return await ensurePromise}finally{ensurePromise=null}}async function _ensurePgserve(){if(activePort!==null&&pgserveServer)return activePort;if(activePort!==null)return activePort;let port=getPort(),reusedPort=await tryReuseLockfile();if(reusedPort!==null)return reusedPort;if(await isPortListening(port,DEFAULT_HOST))return markPortActive(port,!0);mkdirSync6(DATA_DIR,{recursive:!0}),killOrphanedPostgres(DATA_DIR);try{let startedPort=await startPgserveOnPort(port);return registerExitHandler(),startedPort}catch(err){return tryFallbackPorts(port,err)}}async function tryReuseLockfile(){let lockfilePort=readLockfile();if(lockfilePort===null)return null;if(await isPortListening(lockfilePort,DEFAULT_HOST))return markPortActive(lockfilePort,!1);return removeLockfile(),null}function markPortActive(port,writeLock){if(activePort=port,process.env.GENIE_PG_AVAILABLE="true",writeLock)writeLockfile(port);return port}async function tryFallbackPorts(basePort,originalErr){for(let offset=1;offset<=MAX_PORT_RETRIES;offset++){let fallbackPort=basePort+offset;if(await isPortListening(fallbackPort,DEFAULT_HOST))return markPortActive(fallbackPort,!0);try{let startedPort=await startPgserveOnPort(fallbackPort);return registerExitHandler(),startedPort}catch{}}process.env.GENIE_PG_AVAILABLE="false";let message=originalErr instanceof Error?originalErr.message:String(originalErr);throw console.warn(`Warning: pgserve failed to start: ${maskCredentials(message)}`),Error(`pgserve failed to start on port ${basePort} (and fallbacks ${basePort+1}-${basePort+MAX_PORT_RETRIES}): ${maskCredentials(message)}`)}async function startPgserveOnPort(port){let{startMultiTenantServer}=await import("pgserve");return pgserveServer=await startMultiTenantServer({port,host:DEFAULT_HOST,baseDir:DATA_DIR,logLevel:"warn",autoProvision:!0}),activePort=port,ownsLockfile=!0,process.env.GENIE_PG_AVAILABLE="true",writeLockfile(port),port}function registerExitHandler(){if(exitHandlerRegistered)return;exitHandlerRegistered=!0;let cleanup=()=>{if(ownsLockfile)removeLockfile(),ownsLockfile=!1};process.on("exit",cleanup),process.on("SIGINT",()=>{cleanup(),process.exit(130)}),process.on("SIGTERM",()=>{cleanup(),process.exit(143)})}function migrationsDone(){try{let marker=readFileSync8(MIGRATION_MARKER,"utf-8").trim(),currentVersion=process.env.npm_package_version??"";return marker===currentVersion||currentVersion===""&&marker.length>0}catch{return!1}}function markMigrationsDone(){try{let version=process.env.npm_package_version??Date.now().toString();writeFileSync5(MIGRATION_MARKER,version,"utf-8")}catch{}}async function getConnection(){if(sqlClient)return sqlClient;let port=await ensurePgserve(),postgres2=(await Promise.resolve().then(() => (init_src(),exports_src))).default;if(sqlClient=postgres2({host:DEFAULT_HOST,port,database:DB_NAME,username:"postgres",password:"postgres",max:10,idle_timeout:1,connect_timeout:5}),!migrationsDone())await runMigrations(sqlClient),markMigrationsDone();return sqlClient}async function isAvailable2(){try{return await(await getConnection())`SELECT 1`,!0}catch{return!1}}async function shutdown(){if(sqlClient)await sqlClient.end({timeout:5}),sqlClient=null;if(ownsLockfile)removeLockfile(),ownsLockfile=!1}function getDataDir(){return DATA_DIR}function getActivePort(){return activePort??getPort()}function getLockfilePath(){return LOCKFILE_PATH}var DEFAULT_PORT=19642,DEFAULT_HOST="127.0.0.1",MAX_PORT_RETRIES=3,GENIE_HOME2,DATA_DIR,LOCKFILE_PATH,MIGRATION_MARKER,DB_NAME="genie",pgserveServer=null,sqlClient=null,activePort=null,ensurePromise=null,ownsLockfile=!1,exitHandlerRegistered=!1;var init_db=__esm(()=>{init_db_migrations();GENIE_HOME2=process.env.GENIE_HOME??join18(homedir14(),".genie"),DATA_DIR=join18(GENIE_HOME2,"data","pgserve"),LOCKFILE_PATH=join18(GENIE_HOME2,"pgserve.port"),MIGRATION_MARKER=join18(GENIE_HOME2,"pgserve.migrated")});var exports_wish_state={};__export(exports_wish_state,{startGroup:()=>startGroup,resolveRepoPath:()=>resolveRepoPath,resetGroup:()=>resetGroup,isWishComplete:()=>isWishComplete,getState:()=>getState,getOrCreateState:()=>getOrCreateState,getGroupState:()=>getGroupState,findGroupByAssignee:()=>findGroupByAssignee,findAnyGroupByAssignee:()=>findAnyGroupByAssignee,createState:()=>createState,completeGroup:()=>completeGroup,WishStateSchema:()=>WishStateSchema,GroupStatusSchema:()=>GroupStatusSchema,GroupStateSchema:()=>GroupStateSchema});import{execSync as execSync4}from"child_process";import{dirname as dirname5}from"path";function resolveRepoPath(cwd){if(cwd)return cwd;try{let commonDir=execSync4("git rev-parse --path-format=absolute --git-common-dir",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim();return dirname5(commonDir)}catch{return process.cwd()}}function wishFilePath(slug){return`.genie/wishes/${slug}/WISH.md`}function toISO(v){if(v==null)return;if(v instanceof Date)return v.toISOString();return String(v)}async function findParent(sql,slug,repoPath){let wishFile=wishFilePath(slug),rows=await sql`
162
+ `};return resolve4(lo),new Promise(async(r)=>finish=r);async function readable({highWaterMark=16384,start=0,end=1/0}={}){let max=end-start;return start&&await lo.seek(start),new Stream2.Readable({highWaterMark,async read(size){let l=size>max?size-max:size;max-=size;let[{data}]=await lo.read(l);if(this.push(data),data.length<size)this.push(null)}})}async function writable({highWaterMark=16384,start=0}={}){return start&&await lo.seek(start),new Stream2.Writable({highWaterMark,write(chunk,encoding,callback){lo.write(chunk).then(()=>callback(),callback)}})}}).catch(reject)})}var init_large=()=>{};var exports_src={};__export(exports_src,{default:()=>src_default});import os from"os";import fs from"fs";function Postgres(a,b2){let options=parseOptions(a,b2),subscribe2=options.no_subscribe||Subscribe(Postgres,{...options}),ending=!1,queries=queue_default(),connecting=queue_default(),reserved=queue_default(),closed=queue_default(),ended=queue_default(),open2=queue_default(),busy=queue_default(),full=queue_default(),queues={connecting,reserved,closed,ended,open:open2,busy,full},connections=[...Array(options.max)].map(()=>connection_default(options,queues,{onopen,onend,onclose})),sql=Sql(handler);return Object.assign(sql,{get parameters(){return options.parameters},largeObject:largeObject.bind(null,sql),subscribe:subscribe2,CLOSE,END:CLOSE,PostgresError,options,reserve,listen,begin,close:close2,end}),sql;function Sql(handler2){return handler2.debug=options.debug,Object.entries(options.types).reduce((acc,[name,type2])=>{return acc[name]=(x)=>new Parameter(x,type2.to),acc},typed),Object.assign(sql2,{types:typed,typed,unsafe,notify,array,json:json2,file}),sql2;function typed(value,type2){return new Parameter(value,type2)}function sql2(strings,...args){return strings&&Array.isArray(strings.raw)?new Query(strings,args,handler2,cancel):typeof strings==="string"&&!args.length?new Identifier(options.transform.column.to?options.transform.column.to(strings):strings):new Builder(strings,args)}function unsafe(string,args=[],options2={}){return arguments.length===2&&!Array.isArray(args)&&(options2=args,args=[]),new Query([string],args,handler2,cancel,{prepare:!1,...options2,simple:"simple"in options2?options2.simple:args.length===0})}function file(path2,args=[],options2={}){return arguments.length===2&&!Array.isArray(args)&&(options2=args,args=[]),new Query([],args,(query2)=>{fs.readFile(path2,"utf8",(err,string)=>{if(err)return query2.reject(err);query2.strings=[string],handler2(query2)})},cancel,{...options2,simple:"simple"in options2?options2.simple:args.length===0})}}async function listen(name,fn,onlisten){let listener={fn,onlisten},sql2=listen.sql||(listen.sql=Postgres({...options,max:1,idle_timeout:null,max_lifetime:null,fetch_types:!1,onclose(){Object.entries(listen.channels).forEach(([name2,{listeners}])=>{delete listen.channels[name2],Promise.all(listeners.map((l)=>listen(name2,l.fn,l.onlisten).catch(()=>{})))})},onnotify(c,x){c in listen.channels&&listen.channels[c].listeners.forEach((l)=>l.fn(x))}})),channels=listen.channels||(listen.channels={});if(name in channels){channels[name].listeners.push(listener);let result2=await channels[name].result;return listener.onlisten&&listener.onlisten(),{state:result2.state,unlisten}}channels[name]={result:sql2`listen ${sql2.unsafe('"'+name.replace(/"/g,'""')+'"')}`,listeners:[listener]};let result=await channels[name].result;return listener.onlisten&&listener.onlisten(),{state:result.state,unlisten};async function unlisten(){if(name in channels===!1)return;if(channels[name].listeners=channels[name].listeners.filter((x)=>x!==listener),channels[name].listeners.length)return;return delete channels[name],sql2`unlisten ${sql2.unsafe('"'+name.replace(/"/g,'""')+'"')}`}}async function notify(channel,payload){return await sql`select pg_notify(${channel}, ${""+payload})`}async function reserve(){let queue=queue_default(),c=open2.length?open2.shift():await new Promise((resolve4,reject)=>{let query={reserve:resolve4,reject};queries.push(query),closed.length&&connect(closed.shift(),query)});move(c,reserved),c.reserved=()=>queue.length?c.execute(queue.shift()):move(c,reserved),c.reserved.release=!0;let sql2=Sql(handler2);return sql2.release=()=>{c.reserved=null,onopen(c)},sql2;function handler2(q){c.queue===full?queue.push(q):c.execute(q)||move(c,full)}}async function begin(options2,fn){!fn&&(fn=options2,options2="");let queries2=queue_default(),savepoints=0,connection2,prepare=null;try{return await sql.unsafe("begin "+options2.replace(/[^a-z ]/ig,""),[],{onexecute}).execute(),await Promise.race([scope(connection2,fn),new Promise((_,reject)=>connection2.onclose=reject)])}catch(error2){throw error2}async function scope(c,fn2,name){let sql2=Sql(handler2);sql2.savepoint=savepoint,sql2.prepare=(x)=>prepare=x.replace(/[^a-z0-9$-_. ]/gi);let uncaughtError,result;name&&await sql2`savepoint ${sql2(name)}`;try{if(result=await new Promise((resolve4,reject)=>{let x=fn2(sql2);Promise.resolve(Array.isArray(x)?Promise.all(x):x).then(resolve4,reject)}),uncaughtError)throw uncaughtError}catch(e){throw await(name?sql2`rollback to ${sql2(name)}`:sql2`rollback`),e instanceof PostgresError&&e.code==="25P02"&&uncaughtError||e}if(!name)prepare?await sql2`prepare transaction '${sql2.unsafe(prepare)}'`:await sql2`commit`;return result;function savepoint(name2,fn3){if(name2&&Array.isArray(name2.raw))return savepoint((sql3)=>sql3.apply(sql3,arguments));return arguments.length===1&&(fn3=name2,name2=null),scope(c,fn3,"s"+savepoints+++(name2?"_"+name2:""))}function handler2(q){q.catch((e)=>uncaughtError||(uncaughtError=e)),c.queue===full?queries2.push(q):c.execute(q)||move(c,full)}}function onexecute(c){connection2=c,move(c,reserved),c.reserved=()=>queries2.length?c.execute(queries2.shift()):move(c,reserved)}}function move(c,queue){return c.queue.remove(c),queue.push(c),c.queue=queue,queue===open2?c.idleTimer.start():c.idleTimer.cancel(),c}function json2(x){return new Parameter(x,3802)}function array(x,type2){if(!Array.isArray(x))return array(Array.from(arguments));return new Parameter(x,type2||(x.length?inferType(x)||25:0),options.shared.typeArrayMap)}function handler(query){if(ending)return query.reject(Errors.connection("CONNECTION_ENDED",options,options));if(open2.length)return go(open2.shift(),query);if(closed.length)return connect(closed.shift(),query);busy.length?go(busy.shift(),query):queries.push(query)}function go(c,query){return c.execute(query)?move(c,busy):move(c,full)}function cancel(query){return new Promise((resolve4,reject)=>{query.state?query.active?connection_default(options).cancel(query.state,resolve4,reject):query.cancelled={resolve:resolve4,reject}:(queries.remove(query),query.cancelled=!0,query.reject(Errors.generic("57014","canceling statement due to user request")),resolve4())})}async function end({timeout=null}={}){if(ending)return ending;await 1;let timer2;return ending=Promise.race([new Promise((r)=>timeout!==null&&(timer2=setTimeout(destroy,timeout*1000,r))),Promise.all(connections.map((c)=>c.end()).concat(listen.sql?listen.sql.end({timeout:0}):[],subscribe2.sql?subscribe2.sql.end({timeout:0}):[]))]).then(()=>clearTimeout(timer2))}async function close2(){await Promise.all(connections.map((c)=>c.end()))}async function destroy(resolve4){await Promise.all(connections.map((c)=>c.terminate()));while(queries.length)queries.shift().reject(Errors.connection("CONNECTION_DESTROYED",options));resolve4()}function connect(c,query){return move(c,connecting),c.connect(query),c}function onend(c){move(c,ended)}function onopen(c){if(queries.length===0)return move(c,open2);let max=Math.ceil(queries.length/(connecting.length+1)),ready=!0;while(ready&&queries.length&&max-- >0){let query=queries.shift();if(query.reserve)return query.reserve(c);ready=c.execute(query)}ready?move(c,busy):move(c,full)}function onclose(c,e){move(c,closed),c.reserved=null,c.onclose&&(c.onclose(e),c.onclose=null),options.onclose&&options.onclose(c.id),queries.length&&connect(c,queries.shift())}}function parseOptions(a,b2){if(a&&a.shared)return a;let env=process.env,o=(!a||typeof a==="string"?b2:a)||{},{url,multihost}=parseUrl(a),query=[...url.searchParams].reduce((a2,[b3,c])=>(a2[b3]=c,a2),{}),host=o.hostname||o.host||multihost||url.hostname||env.PGHOST||"localhost",port=o.port||url.port||env.PGPORT||5432,user=o.user||o.username||url.username||env.PGUSERNAME||env.PGUSER||osUsername();o.no_prepare&&(o.prepare=!1),query.sslmode&&(query.ssl=query.sslmode,delete query.sslmode),"timeout"in o&&(console.log("The timeout option is deprecated, use idle_timeout instead"),o.idle_timeout=o.timeout),query.sslrootcert==="system"&&(query.ssl="verify-full");let ints=["idle_timeout","connect_timeout","max_lifetime","max_pipeline","backoff","keep_alive"],defaults={max:globalThis.Cloudflare?3:10,ssl:!1,sslnegotiation:null,idle_timeout:null,connect_timeout:30,max_lifetime,max_pipeline:100,backoff,keep_alive:60,prepare:!0,debug:!1,fetch_types:!0,publications:"alltables",target_session_attrs:null};return{host:Array.isArray(host)?host:host.split(",").map((x)=>x.split(":")[0]),port:Array.isArray(port)?port:host.split(",").map((x)=>parseInt(x.split(":")[1]||port)),path:o.path||host.indexOf("/")>-1&&host+"/.s.PGSQL."+port,database:o.database||o.db||(url.pathname||"").slice(1)||env.PGDATABASE||user,user,pass:o.pass||o.password||url.password||env.PGPASSWORD||"",...Object.entries(defaults).reduce((acc,[k,d])=>{let value=k in o?o[k]:(k in query)?query[k]==="disable"||query[k]==="false"?!1:query[k]:env["PG"+k.toUpperCase()]||d;return acc[k]=typeof value==="string"&&ints.includes(k)?+value:value,acc},{}),connection:{application_name:env.PGAPPNAME||"postgres.js",...o.connection,...Object.entries(query).reduce((acc,[k,v])=>((k in defaults)||(acc[k]=v),acc),{})},types:o.types||{},target_session_attrs:tsa(o,url,env),onnotice:o.onnotice,onnotify:o.onnotify,onclose:o.onclose,onparameter:o.onparameter,socket:o.socket,transform:parseTransform(o.transform||{undefined:void 0}),parameters:{},shared:{retries:0,typeArrayMap:{}},...mergeUserTypes(o.types)}}function tsa(o,url,env){let x=o.target_session_attrs||url.searchParams.get("target_session_attrs")||env.PGTARGETSESSIONATTRS;if(!x||["read-write","read-only","primary","standby","prefer-standby"].includes(x))return x;throw Error("target_session_attrs "+x+" is not supported")}function backoff(retries){return(0.5+Math.random()/2)*Math.min(3**retries/100,20)}function max_lifetime(){return 60*(30+Math.random()*30)}function parseTransform(x){return{undefined:x.undefined,column:{from:typeof x.column==="function"?x.column:x.column&&x.column.from,to:x.column&&x.column.to},value:{from:typeof x.value==="function"?x.value:x.value&&x.value.from,to:x.value&&x.value.to},row:{from:typeof x.row==="function"?x.row:x.row&&x.row.from,to:x.row&&x.row.to}}}function parseUrl(url){if(!url||typeof url!=="string")return{url:{searchParams:new Map}};let host=url;host=host.slice(host.indexOf("://")+3).split(/[?/]/)[0],host=decodeURIComponent(host.slice(host.indexOf("@")+1));let urlObj=new URL(url.replace(host,host.split(",")[0]));return{url:{username:decodeURIComponent(urlObj.username),password:decodeURIComponent(urlObj.password),host:urlObj.host,hostname:urlObj.hostname,port:urlObj.port,pathname:urlObj.pathname,searchParams:urlObj.searchParams},multihost:host.indexOf(",")>-1&&host}}function osUsername(){try{return os.userInfo().username}catch(_){return process.env.USERNAME||process.env.USER||process.env.LOGNAME}}var src_default;var init_src=__esm(()=>{init_types3();init_connection();init_query();init_queue();init_errors3();init_large();Object.assign(Postgres,{PostgresError,toPascal,pascal,toCamel,camel,toKebab,kebab,fromPascal,fromCamel,fromKebab,BigInt:{to:20,from:[20],parse:(x)=>BigInt(x),serialize:(x)=>x.toString()}});src_default=Postgres});var exports_db={};__export(exports_db,{shutdown:()=>shutdown,resetConnection:()=>resetConnection,isAvailable:()=>isAvailable2,getLockfilePath:()=>getLockfilePath,getDataDir:()=>getDataDir,getConnection:()=>getConnection,getActivePort:()=>getActivePort,ensurePgserve:()=>ensurePgserve});import{execSync as execSync3}from"child_process";import{existsSync as existsSync14,mkdirSync as mkdirSync6,readFileSync as readFileSync8,renameSync,unlinkSync as unlinkSync3,writeFileSync as writeFileSync5}from"fs";import{createConnection}from"net";import{homedir as homedir13}from"os";import{join as join17}from"path";function maskCredentials(url){return url.replace(/\/\/.*@/,"//***@")}function killOrphanedPostgres(dataDir){let pidFile=join17(dataDir,"postmaster.pid");if(!existsSync14(pidFile))return;try{let content=readFileSync8(pidFile,"utf-8"),pid=Number.parseInt(content.split(`
163
+ `)[0],10);if(Number.isNaN(pid)||pid<=0)return;let cmdline;try{cmdline=execSync3(`ps -o command= -p ${pid} 2>/dev/null`,{encoding:"utf-8"}).trim()}catch{return}if(!cmdline.includes("postgres"))return;try{process.kill(pid,"SIGTERM")}catch{return}let deadline=Date.now()+5000;while(Date.now()<deadline)try{process.kill(pid,0),execSync3("sleep 0.2",{stdio:"ignore"})}catch{return}try{process.kill(pid,"SIGKILL")}catch{}}catch{}}function getPort(){let envPort=process.env.GENIE_PG_PORT;if(envPort){let parsed=Number.parseInt(envPort,10);if(!Number.isNaN(parsed)&&parsed>0&&parsed<65536)return parsed}return DEFAULT_PORT}function isPortListening(port,host){return new Promise((resolve4)=>{let socket=createConnection({port,host},()=>{socket.destroy(),resolve4(!0)});socket.on("error",()=>{socket.destroy(),resolve4(!1)}),socket.setTimeout(1000,()=>{socket.destroy(),resolve4(!1)})})}function readLockfile(){try{let content=readFileSync8(LOCKFILE_PATH,"utf-8").trim(),port=Number.parseInt(content,10);if(!Number.isNaN(port)&&port>0&&port<65536)return port}catch{}return null}function writeLockfile(port){try{mkdirSync6(GENIE_HOME2,{recursive:!0});let tmpPath=`${LOCKFILE_PATH}.tmp.${process.pid}`;writeFileSync5(tmpPath,String(port),"utf-8"),renameSync(tmpPath,LOCKFILE_PATH)}catch{}}function removeLockfile(){try{unlinkSync3(LOCKFILE_PATH)}catch{}}async function ensurePgserve(){if(ensurePromise)return ensurePromise;ensurePromise=_ensurePgserve();try{return await ensurePromise}finally{ensurePromise=null}}async function _ensurePgserve(){if(activePort!==null&&pgserveServer)return activePort;if(activePort!==null)return activePort;let port=getPort(),reusedPort=await tryReuseLockfile();if(reusedPort!==null)return reusedPort;if(await isPortListening(port,DEFAULT_HOST))return markPortActive(port,!0);mkdirSync6(DATA_DIR,{recursive:!0}),killOrphanedPostgres(DATA_DIR);try{let startedPort=await startPgserveOnPort(port);return registerExitHandler(),startedPort}catch(err){return tryFallbackPorts(port,err)}}async function tryReuseLockfile(){let lockfilePort=readLockfile();if(lockfilePort===null)return null;if(await isPortListening(lockfilePort,DEFAULT_HOST))return markPortActive(lockfilePort,!1);return removeLockfile(),null}function markPortActive(port,writeLock){if(activePort=port,process.env.GENIE_PG_AVAILABLE="true",writeLock)writeLockfile(port);return port}async function tryFallbackPorts(basePort,originalErr){for(let offset=1;offset<=MAX_PORT_RETRIES;offset++){let fallbackPort=basePort+offset;if(await isPortListening(fallbackPort,DEFAULT_HOST))return markPortActive(fallbackPort,!0);try{let startedPort=await startPgserveOnPort(fallbackPort);return registerExitHandler(),startedPort}catch{}}process.env.GENIE_PG_AVAILABLE="false";let message=originalErr instanceof Error?originalErr.message:String(originalErr);throw console.warn(`Warning: pgserve failed to start: ${maskCredentials(message)}`),Error(`pgserve failed to start on port ${basePort} (and fallbacks ${basePort+1}-${basePort+MAX_PORT_RETRIES}): ${maskCredentials(message)}`)}async function startPgserveOnPort(port){let{startMultiTenantServer}=await import("pgserve");return pgserveServer=await startMultiTenantServer({port,host:DEFAULT_HOST,baseDir:DATA_DIR,logLevel:"warn",autoProvision:!0}),activePort=port,ownsLockfile=!0,process.env.GENIE_PG_AVAILABLE="true",writeLockfile(port),port}function registerExitHandler(){if(exitHandlerRegistered)return;exitHandlerRegistered=!0;let cleanup=()=>{if(ownsLockfile)removeLockfile(),ownsLockfile=!1};process.on("exit",cleanup),process.on("SIGINT",()=>{cleanup(),process.exit(130)}),process.on("SIGTERM",()=>{cleanup(),process.exit(143)})}function migrationsDone(){try{let marker=readFileSync8(MIGRATION_MARKER,"utf-8").trim(),currentVersion=process.env.npm_package_version??"";return marker===currentVersion||currentVersion===""&&marker.length>0}catch{return!1}}function markMigrationsDone(){try{let version=process.env.npm_package_version??Date.now().toString();writeFileSync5(MIGRATION_MARKER,version,"utf-8")}catch{}}async function getConnection(){if(sqlClient)return sqlClient;let port=await ensurePgserve(),postgres2=(await Promise.resolve().then(() => (init_src(),exports_src))).default,testSchema=process.env.GENIE_TEST_SCHEMA;if(sqlClient=postgres2({host:DEFAULT_HOST,port,database:DB_NAME,username:"postgres",password:"postgres",max:10,idle_timeout:1,connect_timeout:5,...testSchema?{connection:{search_path:`${testSchema}, public`}}:{}}),!migrationsDone())await runMigrations(sqlClient),markMigrationsDone();return sqlClient}async function resetConnection(){if(sqlClient)await sqlClient.end({timeout:5}),sqlClient=null}async function isAvailable2(){try{return await(await getConnection())`SELECT 1`,!0}catch{return!1}}async function shutdown(){if(sqlClient)await sqlClient.end({timeout:5}),sqlClient=null;if(ownsLockfile)removeLockfile(),ownsLockfile=!1}function getDataDir(){return DATA_DIR}function getActivePort(){return activePort??getPort()}function getLockfilePath(){return LOCKFILE_PATH}var DEFAULT_PORT=19642,DEFAULT_HOST="127.0.0.1",MAX_PORT_RETRIES=3,GENIE_HOME2,DATA_DIR,LOCKFILE_PATH,MIGRATION_MARKER,DB_NAME="genie",pgserveServer=null,sqlClient=null,activePort=null,ensurePromise=null,ownsLockfile=!1,exitHandlerRegistered=!1;var init_db=__esm(()=>{init_db_migrations();GENIE_HOME2=process.env.GENIE_HOME??join17(homedir13(),".genie"),DATA_DIR=join17(GENIE_HOME2,"data","pgserve"),LOCKFILE_PATH=join17(GENIE_HOME2,"pgserve.port"),MIGRATION_MARKER=join17(GENIE_HOME2,"pgserve.migrated")});var exports_wish_state={};__export(exports_wish_state,{startGroup:()=>startGroup,resolveRepoPath:()=>resolveRepoPath,resetInProgressGroups:()=>resetInProgressGroups,resetGroup:()=>resetGroup,isWishComplete:()=>isWishComplete,getState:()=>getState,getOrCreateState:()=>getOrCreateState,getGroupState:()=>getGroupState,findGroupByAssignee:()=>findGroupByAssignee,findAnyGroupByAssignee:()=>findAnyGroupByAssignee,createState:()=>createState,completeGroup:()=>completeGroup,WishStateSchema:()=>WishStateSchema,GroupStatusSchema:()=>GroupStatusSchema,GroupStateSchema:()=>GroupStateSchema});import{execSync as execSync4}from"child_process";import{dirname as dirname5}from"path";function resolveRepoPath(cwd){if(cwd)return cwd;try{let commonDir=execSync4("git rev-parse --path-format=absolute --git-common-dir",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim();return dirname5(commonDir)}catch{return process.cwd()}}function wishFilePath(slug){return`.genie/wishes/${slug}/WISH.md`}function toISO(v){if(v==null)return;if(v instanceof Date)return v.toISOString();return String(v)}async function findParent(sql,slug,repoPath){let wishFile=wishFilePath(slug),rows=await sql`
164
164
  SELECT * FROM tasks
165
165
  WHERE wish_file = ${wishFile} AND repo_path = ${repoPath} AND parent_id IS NULL
166
166
  LIMIT 1
@@ -237,7 +237,15 @@ ${errCtx.stack}`;d.reject(err)}else d.resolve(msg)}});return sub.requestSubject=
237
237
  `,depsMap={};for(let dep of deps){let taskId=dep.task_id;if(!depsMap[taskId])depsMap[taskId]=[];depsMap[taskId].push(dep.dep_group)}let actors=await sql`
238
238
  SELECT task_id, actor_id FROM task_actors
239
239
  WHERE task_id = ANY(${childIds}) AND role = 'assignee'
240
- `,assigneeMap={};for(let actor of actors)assigneeMap[actor.task_id]=actor.actor_id;let groups={};for(let child of children){let{id,group_name:groupName}=child;groups[groupName]={status:child.status,assignee:assigneeMap[id],dependsOn:depsMap[id]??[],startedAt:toISO(child.started_at),completedAt:toISO(child.ended_at)}}return{wish:slug,groups,createdAt:toISO(parent.created_at)??"",updatedAt:toISO(parent.updated_at)??""}}async function getGroupState(slug,groupName,cwd){let state2=await getState(slug,cwd);if(!state2)return null;return state2.groups[groupName]??null}async function isWishComplete(slug,cwd){let state2=await getState(slug,cwd);if(!state2)return!1;let groups=Object.values(state2.groups);return groups.length>0&&groups.every((g)=>g.status==="done")}var GroupStatusSchema,GroupStateSchema,WishStateSchema;var init_wish_state=__esm(()=>{init_zod();init_db();GroupStatusSchema=exports_external.enum(["blocked","ready","in_progress","done"]),GroupStateSchema=exports_external.object({status:GroupStatusSchema,assignee:exports_external.string().optional(),dependsOn:exports_external.array(exports_external.string()).default([]),startedAt:exports_external.string().optional(),completedAt:exports_external.string().optional()}),WishStateSchema=exports_external.object({wish:exports_external.string(),groups:exports_external.record(exports_external.string(),GroupStateSchema),createdAt:exports_external.string(),updatedAt:exports_external.string()})});var exports_protocol_router_spawn={};__export(exports_protocol_router_spawn,{spawnWorkerFromTemplate:()=>spawnWorkerFromTemplate,injectResumeContext:()=>injectResumeContext});import{exec as exec2}from"child_process";import{readFile as readFile6}from"fs/promises";import{join as join19}from"path";import{promisify as promisify2}from"util";async function resolveParentSession(_repoPath,team){let teamConfig=await getTeam2(team);if(teamConfig?.nativeTeamParentSessionId)return teamConfig.nativeTeamParentSessionId;return await discoverClaudeSessionId()??`genie-${team}`}function buildSpawnParams(template,parentSessionId,spawnColor,resumeSessionId){let isClaude=template.provider==="claude",sessionName=template.role?`${template.team}-${template.role}`:void 0,newSessionId=isClaude&&!resumeSessionId?crypto.randomUUID():void 0,params={provider:template.provider,team:template.team,role:template.role,skill:template.skill,extraArgs:template.extraArgs,sessionId:newSessionId,resume:isClaude?resumeSessionId:void 0,name:sessionName};if(isClaude)params.nativeTeam={enabled:!0,parentSessionId,color:spawnColor,agentType:template.role??"general-purpose",agentName:template.role};return params}function buildFullCommand(launch){if(launch.env&&Object.keys(launch.env).length>0)return`env ${Object.entries(launch.env).map(([k,v])=>`${k}=${v}`).join(" ")} ${launch.command}`;return launch.command}async function generateWorkerId(team,role){let base=role?`${team}-${role}`:team;return(await list()).some((w)=>w.id===base)?`${base}-${crypto.randomUUID().slice(0,8)}`:base}async function spawnPaneInSession(session,team,repoPath,fullCommand){let teamWindow=null;try{teamWindow=await ensureTeamWindow(session,team,repoPath)}catch{}let splitTarget=teamWindow?`-t '${teamWindow.windowId}'`:"",{stdout}=await execAsync(`tmux split-window -d ${splitTarget} -P -F '#{pane_id}' ${fullCommand}`),paneId=stdout.trim(),layoutTarget=`${session}:${teamWindow?.windowName??""}`;if(!teamWindow){let wins=await listWindows(session);layoutTarget=wins[0]?wins[0].id:`${session}:`}try{await execAsync(`tmux ${buildLayoutCommand(layoutTarget,resolveLayoutMode())}`)}catch{}return{paneId,teamWindow}}async function spawnWorkerFromTemplate(template,resumeSessionId){let repoPath=template.cwd??process.cwd(),team=template.team,parentSessionId=await resolveParentSession(repoPath,team);await ensureNativeTeam(team,`Genie team: ${team}`,parentSessionId);let spawnColor=await assignColor(team),params=buildSpawnParams(template,parentSessionId,spawnColor,resumeSessionId),launch=buildLaunchCommand(validateSpawnParams(params)),fullCommand=buildFullCommand(launch),workerId=await generateWorkerId(team,template.role),session=await getCurrentSessionName()??team,{paneId,teamWindow}=await spawnPaneInSession(session,team,repoPath,fullCommand),now=new Date().toISOString(),agentName=template.role??"worker",isClaude=template.provider==="claude",effectiveSessionId=resumeSessionId??params.sessionId,workerEntry={id:workerId,paneId,session,provider:template.provider,transport:"tmux",role:template.role,skill:template.skill,team,worktree:null,startedAt:now,state:"spawning",lastStateChange:now,repoPath,claudeSessionId:effectiveSessionId,nativeTeamEnabled:isClaude,nativeAgentId:`${agentName}@${team}`,nativeColor:spawnColor,parentSessionId,window:teamWindow?.windowName,windowName:teamWindow?.windowName,windowId:teamWindow?.windowId};if(await register(workerEntry),await registerNativeMember(team,{agentName,agentType:template.role??"general-purpose",color:spawnColor??"blue",tmuxPaneId:paneId,cwd:repoPath}),await writeNativeInbox(team,"team-lead",{from:agentName,text:`Worker ${agentName} (${template.provider}) auto-spawned${resumeSessionId?" with --resume":""}. Ready for tasks.`,summary:`${agentName} auto-spawned`,timestamp:now,color:spawnColor??"blue",read:!1}),spawnColor)await applyPaneColor(paneId,spawnColor,teamWindow?.windowId);return await injectResumeContext(repoPath,workerId,agentName,team),{worker:workerEntry,paneId,workerId}}function extractGroupSection(content,groupName){let escaped=groupName.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),pattern=new RegExp(`^### Group ${escaped}:`,"m"),match=content.match(pattern);if(!match||match.index===void 0)return null;let start=match.index,nextBoundary=content.slice(start).slice(1).search(/^### Group \d|^---$/m),end=nextBoundary!==-1?start+1+nextBoundary:content.length;return content.slice(start,end).trim()}async function getRecentGitLog(repoPath,count=3){try{let{stdout}=await execAsync(`git -C '${repoPath}' log --oneline -${count} 2>/dev/null`);return stdout.trim()}catch{return""}}async function getGitStatus(repoPath){try{let{stdout}=await execAsync(`git -C '${repoPath}' status --short 2>/dev/null`);return stdout.trim()}catch{return""}}async function injectResumeContext(repoPath,workerId,agentName,_team){try{let match=await findAnyGroupByAssignee(workerId,repoPath)??await findAnyGroupByAssignee(agentName,repoPath);if(!match)return;let{slug,groupName,group}=match,wishPath=join19(repoPath,".genie","wishes",slug,"WISH.md"),groupSection="";try{let wishContent=await readFile6(wishPath,"utf-8");groupSection=extractGroupSection(wishContent,groupName)??""}catch{}let gitLog=await getRecentGitLog(repoPath),gitStatus=await getGitStatus(repoPath),resumePrompt=[`RESUME CONTEXT: You were working on wish "${slug}", group "${groupName}".`,`Status: ${group.status}. Started at: ${group.startedAt??"unknown"}.`,`Wish file: .genie/wishes/${slug}/WISH.md`,"",groupSection?`Group section:
240
+ `,assigneeMap={};for(let actor of actors)assigneeMap[actor.task_id]=actor.actor_id;let groups={};for(let child of children){let{id,group_name:groupName}=child;groups[groupName]={status:child.status,assignee:assigneeMap[id],dependsOn:depsMap[id]??[],startedAt:toISO(child.started_at),completedAt:toISO(child.ended_at)}}return{wish:slug,groups,createdAt:toISO(parent.created_at)??"",updatedAt:toISO(parent.updated_at)??""}}async function getGroupState(slug,groupName,cwd){let state2=await getState(slug,cwd);if(!state2)return null;return state2.groups[groupName]??null}async function isWishComplete(slug,cwd){let state2=await getState(slug,cwd);if(!state2)return!1;let groups=Object.values(state2.groups);return groups.length>0&&groups.every((g)=>g.status==="done")}async function resetInProgressGroups(slug,cwd){let sql=await getConnection(),repoPath=resolveRepoPath(cwd),parent=await findParent(sql,slug,repoPath);if(!parent)return 0;let now=new Date,inProgress=await sql`
241
+ SELECT id FROM tasks
242
+ WHERE parent_id = ${parent.id} AND status = 'in_progress'
243
+ `;if(inProgress.length===0)return 0;let ids=inProgress.map((r)=>r.id);return await sql`
244
+ UPDATE tasks SET status = 'ready', started_at = NULL, updated_at = ${now}
245
+ WHERE id = ANY(${ids})
246
+ `,await sql`
247
+ DELETE FROM task_actors WHERE task_id = ANY(${ids}) AND role = 'assignee'
248
+ `,ids.length}var GroupStatusSchema,GroupStateSchema,WishStateSchema;var init_wish_state=__esm(()=>{init_zod();init_db();GroupStatusSchema=exports_external.enum(["blocked","ready","in_progress","done"]),GroupStateSchema=exports_external.object({status:GroupStatusSchema,assignee:exports_external.string().optional(),dependsOn:exports_external.array(exports_external.string()).default([]),startedAt:exports_external.string().optional(),completedAt:exports_external.string().optional()}),WishStateSchema=exports_external.object({wish:exports_external.string(),groups:exports_external.record(exports_external.string(),GroupStateSchema),createdAt:exports_external.string(),updatedAt:exports_external.string()})});var exports_team_manager={};__export(exports_team_manager,{validateBranchName:()=>validateBranchName,updateTeamConfig:()=>updateTeamConfig,setTeamStatus:()=>setTeamStatus,pruneStaleWorktrees:()=>pruneStaleWorktrees,listTeams:()=>listTeams2,listMembers:()=>listMembers,killTeamMembers:()=>killTeamMembers,hireAgent:()=>hireAgent,getTeam:()=>getTeam2,fireAgent:()=>fireAgent,disbandTeam:()=>disbandTeam,createTeam:()=>createTeam});import{existsSync as existsSync15}from"fs";import{mkdir as mkdir6,readFile as readFile5,readdir as readdir2,rm as rm3,unlink as unlink4,writeFile as writeFile5}from"fs/promises";import{homedir as homedir14}from"os";import path2,{join as join18}from"path";var{$:$3}=globalThis.Bun;function getGenieDir2(){return process.env.GENIE_HOME??join18(homedir14(),".genie")}function teamsDir(){return join18(getGenieDir2(),"teams")}function safeFileName(name){return name.replace(/\//g,"--")}function teamFilePath(name){let safeName=safeFileName(path2.basename(name)===name?name:name);return join18(teamsDir(),`${safeName}.json`)}function getWorktreeBase(repoPath){let base=loadGenieConfigSync().terminal?.worktreeBase;if(base&&base!==".worktrees"){if(path2.isAbsolute(base))return base;return join18(repoPath,base)}let projectName=path2.basename(repoPath);return join18(getGenieDir2(),"worktrees",projectName)}function validateBranchName(name){let errors3=[];if(/\s/.test(name))errors3.push("contains spaces");if(name.includes(".."))errors3.push('contains ".."');if(name.includes("~"))errors3.push('contains "~"');if(name.includes("^"))errors3.push('contains "^"');if(name.includes(":"))errors3.push('contains ":"');if(name.includes("?"))errors3.push('contains "?"');if(name.includes("*"))errors3.push('contains "*"');if(name.includes("["))errors3.push('contains "["');if(name.includes("\\"))errors3.push('contains "\\"');if(/[\x00-\x1f\x7f]/.test(name))errors3.push("contains control characters");if(name.endsWith(".lock"))errors3.push('ends with ".lock"');if(name.endsWith("/"))errors3.push('ends with "/"');if(name.endsWith("."))errors3.push('ends with "."');if(name.startsWith("-"))errors3.push('starts with "-"');if(errors3.length>0)throw Error(`Invalid team name '${name}': must be a valid git branch name (${errors3.join(", ")})`)}async function killWorkersByName(agentName,teamName){let matches=(await list()).filter((w)=>(w.role===agentName||w.id===agentName)&&(!teamName||w.team===teamName));for(let w of matches){try{if(w.paneId&&w.paneId!=="inline"){let{execSync:execSync5}=__require("child_process");execSync5(`tmux kill-pane -t ${w.paneId}`,{stdio:"ignore"})}}catch{}await unregister(w.id)}}async function ensureWorktree(repoPath,branchName,worktreePath,baseBranch){try{await $3`git -C ${repoPath} fetch origin ${baseBranch}`.quiet()}catch{}if(await mkdir6(path2.dirname(worktreePath),{recursive:!0}),existsSync15(worktreePath))return;let branchExists=!1;try{await $3`git -C ${repoPath} rev-parse --verify ${branchName}`.quiet(),branchExists=!0}catch{if(!branchExists)try{await $3`git -C ${repoPath} branch ${branchName} origin/${baseBranch}`.quiet()}catch{try{await $3`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet()}catch{await $3`git -C ${repoPath} branch ${branchName}`.quiet()}}}await $3`git clone --shared --branch ${branchName} ${repoPath} ${worktreePath}`.quiet();try{let userName=(await $3`git -C ${repoPath} config user.name`.quiet()).text().trim(),userEmail=(await $3`git -C ${repoPath} config user.email`.quiet()).text().trim();if(userName)await $3`git -C ${worktreePath} config user.name ${userName}`.quiet();if(userEmail)await $3`git -C ${worktreePath} config user.email ${userEmail}`.quiet()}catch{}}async function createTeam(name,repo,baseBranch="dev"){validateBranchName(name);let repoPath=path2.resolve(repo),dir=teamsDir();await mkdir6(dir,{recursive:!0});let filePath=teamFilePath(name);if(existsSync15(filePath)){let content=await readFile5(filePath,"utf-8");return JSON.parse(content)}let worktreeBase=getWorktreeBase(repoPath),worktreePath=join18(worktreeBase,name);await ensureWorktree(repoPath,name,worktreePath,baseBranch);let now=new Date().toISOString(),config={name,repo:repoPath,baseBranch,worktreePath,members:[],status:"in_progress",createdAt:now};if(isInsideClaudeCode()){config.nativeTeamsEnabled=!0;try{let result=await registerAsTeamLead(name);config.nativeTeamParentSessionId=result.sessionId}catch{}}return await writeFile5(filePath,JSON.stringify(config,null,2)),config}async function hireAgent(teamName,agentName){let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);let added;if(agentName==="council")added=BUILTIN_COUNCIL_MEMBERS.map((m)=>m.name).filter((n)=>!config.members.includes(n)),config.members.push(...added);else{if(config.members.includes(agentName))return[];config.members.push(agentName),added=[agentName]}let filePath=teamFilePath(teamName);return await writeFile5(filePath,JSON.stringify(config,null,2)),added}async function fireAgent(teamName,agentName){let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);let idx=config.members.indexOf(agentName);if(idx===-1)return!1;config.members.splice(idx,1);let filePath=teamFilePath(teamName);await writeFile5(filePath,JSON.stringify(config,null,2));try{await killWorkersByName(agentName)}catch{}return!0}async function disbandTeam(teamName){let config=await getTeam2(teamName);if(!config)return!1;try{await deleteNativeTeam(teamName)}catch{}for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}if(config.wishSlug)try{let resetCount=await(await Promise.resolve().then(() => (init_wish_state(),exports_wish_state))).resetInProgressGroups(config.wishSlug,config.repo);if(resetCount>0)console.log(` Reset ${resetCount} in-progress group(s) for wish "${config.wishSlug}"`)}catch{}if(config.worktreePath&&existsSync15(config.worktreePath))try{await rm3(config.worktreePath,{recursive:!0,force:!0})}catch{}let filePath=teamFilePath(teamName);try{await unlink4(filePath)}catch{return!1}return await pruneStaleWorktrees(config.repo),!0}async function pruneStaleWorktrees(_repoPath){let dir=teamsDir(),files;try{files=await readdir2(dir)}catch{return}for(let file of files){if(!file.endsWith(".json"))continue;try{let content=await readFile5(join18(dir,file),"utf-8"),config=JSON.parse(content);if(config.worktreePath&&!existsSync15(config.worktreePath)){try{await deleteNativeTeam(config.name)}catch{}await unlink4(join18(dir,file))}}catch{}}}async function updateTeamConfig(name,config){let filePath=teamFilePath(name);await writeFile5(filePath,JSON.stringify(config,null,2))}async function getTeam2(name){try{let content=await readFile5(teamFilePath(name),"utf-8");return JSON.parse(content)}catch{return null}}async function listTeams2(){let dir=teamsDir();try{let files=await readdir2(dir),teams=[];for(let file of files){if(!file.endsWith(".json"))continue;try{let content=await readFile5(join18(dir,file),"utf-8");teams.push(JSON.parse(content))}catch{}}return teams}catch{return[]}}async function listMembers(teamName){let config=await getTeam2(teamName);if(!config)return null;return config.members}async function killTeamMembers(teamName){let config=await getTeam2(teamName);if(!config)return;for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}}async function setTeamStatus(teamName,status){let filePath=teamFilePath(teamName),release=await acquireLock(filePath);try{let config=await getTeam2(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);config.status=status,await writeFile5(filePath,JSON.stringify(config,null,2))}finally{await release()}}var init_team_manager=__esm(()=>{init_agent_registry();init_builtin_agents();init_claude_native_teams();init_file_lock();init_genie_config2()});var exports_protocol_router_spawn={};__export(exports_protocol_router_spawn,{spawnWorkerFromTemplate:()=>spawnWorkerFromTemplate,injectResumeContext:()=>injectResumeContext});import{exec as exec2}from"child_process";import{readFile as readFile6}from"fs/promises";import{join as join19}from"path";import{promisify as promisify2}from"util";async function resolveParentSession(_repoPath,team){let teamConfig=await getTeam2(team);if(teamConfig?.nativeTeamParentSessionId)return teamConfig.nativeTeamParentSessionId;return await discoverClaudeSessionId()??`genie-${team}`}function buildSpawnParams(template,parentSessionId,spawnColor,resumeSessionId){let isClaude=template.provider==="claude",sessionName=template.role?`${template.team}-${template.role}`:void 0,newSessionId=isClaude&&!resumeSessionId?crypto.randomUUID():void 0,params={provider:template.provider,team:template.team,role:template.role,skill:template.skill,extraArgs:template.extraArgs,sessionId:newSessionId,resume:isClaude?resumeSessionId:void 0,name:sessionName};if(isClaude)params.nativeTeam={enabled:!0,parentSessionId,color:spawnColor,agentType:template.role??"general-purpose",agentName:template.role};return params}function buildFullCommand(launch){if(launch.env&&Object.keys(launch.env).length>0)return`env ${Object.entries(launch.env).map(([k,v])=>`${k}=${v}`).join(" ")} ${launch.command}`;return launch.command}async function generateWorkerId(team,role){let base=role?`${team}-${role}`:team;return(await list()).some((w)=>w.id===base)?`${base}-${crypto.randomUUID().slice(0,8)}`:base}async function spawnPaneInSession(session,team,repoPath,fullCommand){let teamWindow=null;try{teamWindow=await ensureTeamWindow(session,team,repoPath)}catch{}let splitTarget=teamWindow?`-t '${teamWindow.windowId}'`:"",{stdout}=await execAsync(`tmux split-window -d ${splitTarget} -P -F '#{pane_id}' ${fullCommand}`),paneId=stdout.trim(),layoutTarget=`${session}:${teamWindow?.windowName??""}`;if(!teamWindow){let wins=await listWindows(session);layoutTarget=wins[0]?wins[0].id:`${session}:`}try{await execAsync(`tmux ${buildLayoutCommand(layoutTarget,resolveLayoutMode())}`)}catch{}return{paneId,teamWindow}}async function spawnWorkerFromTemplate(template,resumeSessionId){let repoPath=template.cwd??process.cwd(),team=template.team,parentSessionId=await resolveParentSession(repoPath,team);await ensureNativeTeam(team,`Genie team: ${team}`,parentSessionId);let spawnColor=await assignColor(team),params=buildSpawnParams(template,parentSessionId,spawnColor,resumeSessionId),launch=buildLaunchCommand(validateSpawnParams(params)),fullCommand=buildFullCommand(launch),workerId=await generateWorkerId(team,template.role),session=await getCurrentSessionName()??team,{paneId,teamWindow}=await spawnPaneInSession(session,team,repoPath,fullCommand),now=new Date().toISOString(),agentName=template.role??"worker",isClaude=template.provider==="claude",effectiveSessionId=resumeSessionId??params.sessionId,workerEntry={id:workerId,paneId,session,provider:template.provider,transport:"tmux",role:template.role,skill:template.skill,team,worktree:null,startedAt:now,state:"spawning",lastStateChange:now,repoPath,claudeSessionId:effectiveSessionId,nativeTeamEnabled:isClaude,nativeAgentId:`${agentName}@${team}`,nativeColor:spawnColor,parentSessionId,window:teamWindow?.windowName,windowName:teamWindow?.windowName,windowId:teamWindow?.windowId};if(await register(workerEntry),await registerNativeMember(team,{agentName,agentType:template.role??"general-purpose",color:spawnColor??"blue",tmuxPaneId:paneId,cwd:repoPath}),await writeNativeInbox(team,"team-lead",{from:agentName,text:`Worker ${agentName} (${template.provider}) auto-spawned${resumeSessionId?" with --resume":""}. Ready for tasks.`,summary:`${agentName} auto-spawned`,timestamp:now,color:spawnColor??"blue",read:!1}),spawnColor)await applyPaneColor(paneId,spawnColor,teamWindow?.windowId);return await injectResumeContext(repoPath,workerId,agentName,team),{worker:workerEntry,paneId,workerId}}function extractGroupSection(content,groupName){let escaped=groupName.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),pattern=new RegExp(`^### Group ${escaped}:`,"m"),match=content.match(pattern);if(!match||match.index===void 0)return null;let start=match.index,nextBoundary=content.slice(start).slice(1).search(/^### Group \d|^---$/m),end=nextBoundary!==-1?start+1+nextBoundary:content.length;return content.slice(start,end).trim()}async function getRecentGitLog(repoPath,count=3){try{let{stdout}=await execAsync(`git -C '${repoPath}' log --oneline -${count} 2>/dev/null`);return stdout.trim()}catch{return""}}async function getGitStatus(repoPath){try{let{stdout}=await execAsync(`git -C '${repoPath}' status --short 2>/dev/null`);return stdout.trim()}catch{return""}}async function injectResumeContext(repoPath,workerId,agentName,_team){try{let match=await findAnyGroupByAssignee(workerId,repoPath)??await findAnyGroupByAssignee(agentName,repoPath);if(!match)return;let{slug,groupName,group}=match,wishPath=join19(repoPath,".genie","wishes",slug,"WISH.md"),groupSection="";try{let wishContent=await readFile6(wishPath,"utf-8");groupSection=extractGroupSection(wishContent,groupName)??""}catch{}let gitLog=await getRecentGitLog(repoPath),gitStatus=await getGitStatus(repoPath),resumePrompt=[`RESUME CONTEXT: You were working on wish "${slug}", group "${groupName}".`,`Status: ${group.status}. Started at: ${group.startedAt??"unknown"}.`,`Wish file: .genie/wishes/${slug}/WISH.md`,"",groupSection?`Group section:
241
249
  ${groupSection}`:"","",gitLog?`Last git log:
242
250
  ${gitLog}`:"","",gitStatus?`Uncommitted changes:
243
251
  ${gitStatus}`:"","","Pick up where you left off. Read the wish file for full context."].filter(Boolean).join(`
@@ -1222,7 +1230,7 @@ History for "${schedule.name}":
1222
1230
  Tags: ${tags.map((t)=>t.name).join(", ")}`);let blockers=await ts.getBlockers(task.id,task.repoPath);if(blockers.length>0){console.log(`
1223
1231
  Dependencies:`);for(let dep of blockers){let depTask=await ts.getTask(dep.dependsOnId,task.repoPath),label=depTask?`#${depTask.seq} ${depTask.title}`:dep.dependsOnId;console.log(` ${dep.depType}: ${label}`)}}let stageLog=await ts.getStageLog(task.id,task.repoPath);if(stageLog.length>0){console.log(`
1224
1232
  Stage History:`);for(let entry of stageLog.slice(0,10)){let who=entry.actorId??"system";console.log(` ${formatTimestamp3(entry.createdAt)}: ${entry.fromStage??"(new)"} \u2192 ${entry.toStage} by ${who}`)}}}async function printTaskMessages(task){let ts=await getTaskService6(),conv=await ts.findOrCreateConversation({linkedEntity:"task",linkedEntityId:task.id,name:`Task #${task.seq}`}),messages2=await ts.getMessages(conv.id,{limit:20});if(messages2.length>0){console.log(`
1225
- Messages:`);for(let msg of messages2){let time=formatTimestamp3(msg.createdAt),reply=msg.replyToId?` (reply to #${msg.replyToId})`:"";console.log(` [${time}] ${msg.senderId}: ${msg.body}${reply}`)}}}async function printTaskDetail(task){printTaskFields(task),await printTaskRelations(task),await printTaskMessages(task),console.log("")}async function handleTaskCreate(title,options){let ts=await getTaskService6(),actor=currentActor2(),repoPath,projectId;if(options.project){let project=await ts.getProjectByName(options.project);if(!project)project=await ts.createProject({name:options.project});projectId=project.id,repoPath=project.repoPath??void 0}let parentId;if(options.parent){if(parentId=await ts.resolveTaskId(options.parent,repoPath)??void 0,!parentId)console.error(`Error: Parent task not found: ${options.parent}`),process.exit(1)}let task=await ts.createTask({title,typeId:options.type,priority:options.priority,dueDate:options.due,startDate:options.start,parentId,description:options.description,estimatedEffort:options.effort},repoPath,projectId);if(await ts.assignTask(task.id,actor,"creator",{},task.repoPath),options.assign)await ts.assignTask(task.id,localActor2(options.assign),"assignee",{},task.repoPath);if(options.tags){let tagIds=options.tags.split(",").map((t)=>t.trim());await ts.tagTask(task.id,tagIds,actor,task.repoPath)}if(options.comment)await ts.commentOnTask(task.id,actor,options.comment,task.repoPath);if(console.log(`Created task #${task.seq}: ${task.title}`),console.log(` ID: ${task.id}`),console.log(` Stage: ${task.stage} | Priority: ${task.priority}`),options.due)console.log(` Due: ${options.due}`)}function registerTaskCommands(program2){let task=program2.command("task").description("Task lifecycle management");task.command("create <title>").description("Create a new task").option("--type <type>","Task type","software").option("--priority <priority>","Priority: urgent, high, normal, low","normal").option("--due <date>","Due date (YYYY-MM-DD)").option("--start <date>","Start date (YYYY-MM-DD)").option("--tags <tags>","Comma-separated tag IDs").option("--parent <id>","Parent task ID or #seq").option("--assign <name>","Assign to local actor").option("--description <text>","Task description").option("--effort <effort>",'Estimated effort (e.g., "2h", "3 points")').option("--comment <msg>","Initial comment on the task").option("--project <name>","Create task in a specific project (overrides CWD)").action(async(title,options)=>{try{await handleTaskCreate(title,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("list").description("List tasks with filters").option("--stage <stage>","Filter by stage").option("--type <type>","Filter by type").option("--status <status>","Filter by status").option("--priority <priority>","Filter by priority").option("--release <release>","Filter by release").option("--due-before <date>","Filter by due date").option("--mine","Show only tasks assigned to me").option("--project <name>","Show tasks for a specific project").option("--all","Show tasks from ALL projects").option("--json","Output as JSON").action(async(options)=>{try{let ts=await getTaskService6(),filters={stage:options.stage,typeId:options.type,status:options.status,priority:options.priority,releaseId:options.release,dueBefore:options.dueBefore,projectName:options.project,allProjects:options.all},tasks;if(options.mine)tasks=await ts.listTasksForActor(currentActor2(),filters);else tasks=await ts.listTasks(filters);if(options.json){console.log(JSON.stringify(tasks,null,2));return}printTaskList(tasks,options.all)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("show <id>").description("Show task detail (accepts task-id or #seq)").option("--json","Output as JSON").action(async(id,options)=>{try{let t=await(await getTaskService6()).getTask(id);if(!t)console.error(`Error: Task not found: ${id}`),process.exit(1);if(options.json){console.log(JSON.stringify(t,null,2));return}await printTaskDetail(t)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("move <id>").description("Move task to a new stage").requiredOption("--to <stage>","Target stage").option("--comment <msg>","Comment on the move").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.moveTask(id,options.to,actor,options.comment);console.log(`Moved task #${t.seq} to stage "${t.stage}".`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("assign <id>").description("Assign an actor to a task").requiredOption("--to <name>","Actor name").option("--role <role>","Actor role","assignee").option("--comment <msg>","Comment on the assignment").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2();if(await ts.assignTask(id,localActor2(options.to),options.role,{}),options.comment)await ts.commentOnTask(id,actor,options.comment);console.log(`Assigned "${options.to}" as ${options.role??"assignee"} on task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("tag <id> <tags...>").description("Add tags to a task").action(async(id,tags)=>{try{await(await getTaskService6()).tagTask(id,tags,currentActor2()),console.log(`Tagged task ${id} with: ${tags.join(", ")}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("comment <id> <message>").description("Add a comment to a task").option("--reply-to <msgId>","Reply to a specific message ID").action(async(id,message,options)=>{try{let ts=await getTaskService6(),replyTo=options.replyTo?Number(options.replyTo):void 0,msg=await ts.commentOnTask(id,currentActor2(),message,void 0,replyTo);console.log(`Comment #${msg.id} added to task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("block <id>").description("Mark task as blocked").requiredOption("--reason <reason>","Reason for blocking").option("--comment <msg>","Additional comment").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.blockTask(id,options.reason,actor,options.comment);console.log(`Task #${t.seq} blocked: ${options.reason}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unblock <id>").description("Unblock a task").option("--comment <msg>","Comment on unblock").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.unblockTask(id,actor,options.comment);console.log(`Task #${t.seq} unblocked.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("done <id>").description("Mark task as done").option("--comment <msg>","Comment on completion").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.markDone(id,actor,options.comment);console.log(`Task #${t.seq} marked as done.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("checkout <id>").description("Atomically claim a task for execution").action(async(id)=>{try{let ts=await getTaskService6(),runId=getRunId(),t=await ts.checkoutTask(id,runId);console.log(`Checked out task #${t.seq} for run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("release <id>").description("Release task checkout claim").action(async(id)=>{try{let ts=await getTaskService6(),runId=getRunId(),t=await ts.releaseTask(id,runId);console.log(`Released task #${t.seq} from run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unlock <id>").description("Force-release a stale checkout (admin override)").action(async(id)=>{try{let t=await(await getTaskService6()).forceUnlockTask(id);console.log(`Force-unlocked task #${t.seq}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("dep <id>").description("Manage task dependencies").option("--depends-on <id2>","This task depends on id2").option("--blocks <id2>","This task blocks id2").option("--relates-to <id2>","This task relates to id2").option("--remove <id2>","Remove dependency on id2").action(async(id,options)=>{try{let ts=await getTaskService6();if(options.remove){if(await ts.removeDependency(id,options.remove))console.log(`Removed dependency between ${id} and ${options.remove}.`);else console.log("No dependency found to remove.");return}if(options.dependsOn)await ts.addDependency(id,options.dependsOn,"depends_on"),console.log(`${id} now depends on ${options.dependsOn}.`);if(options.blocks)await ts.addDependency(id,options.blocks,"blocks"),console.log(`${id} now blocks ${options.blocks}.`);if(options.relatesTo)await ts.addDependency(id,options.relatesTo,"relates_to"),console.log(`${id} now relates to ${options.relatesTo}.`);if(!options.dependsOn&&!options.blocks&&!options.relatesTo)console.error("Error: Specify --depends-on, --blocks, --relates-to, or --remove."),process.exit(1)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}init_team_manager();import{existsSync as existsSync22}from"fs";import{copyFile as copyFile2,cp,mkdir as mkdir11}from"fs/promises";import{join as join35,resolve as resolve6}from"path";function registerTeamNamespace(program2){let team=program2.command("team").description("Team lifecycle management");team.command("create <name>").description("Create a new team with a git worktree").requiredOption("--repo <path>","Path to the git repository").option("--branch <branch>","Base branch to create from","dev").option("--wish <slug>","Wish slug \u2014 auto-spawns a task leader with wish context").option("--session <name>","Tmux session name (avoids session explosion on parallel creates)").action(async(name,options)=>{try{await handleTeamCreate(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("hire <agent>").description('Add an agent to a team ("council" hires all 10 council members)').option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);let added=await hireAgent(teamName,agent);if(added.length===0)console.log(`Agent "${agent}" is already a member of "${teamName}".`);else if(agent==="council"){console.log(`Hired ${added.length} council members to "${teamName}":`);for(let name of added)console.log(` + ${name}`)}else console.log(`Hired "${agent}" to team "${teamName}".`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("fire <agent>").description("Remove an agent from a team").option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);if(await fireAgent(teamName,agent))console.log(`Fired "${agent}" from team "${teamName}".`);else console.error(`Agent "${agent}" is not a member of "${teamName}".`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("ls [name]").alias("list").description("List teams or members of a team").option("--json","Output as JSON").action(async(name,options)=>{try{if(name)await printMembers(name,options.json);else await printTeams(options.json)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("disband <name>").description("Disband a team: kill members, remove worktree, delete config").action(async(name)=>{try{if(await disbandTeam(name))console.log(`Team "${name}" disbanded.`);else console.error(`Team "${name}" not found.`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("done <name>").description("Mark a team as done and kill all members").action(async(name)=>{try{await setTeamStatus(name,"done"),await killTeamMembers(name),console.log(`Team "${name}" marked as done. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("blocked <name>").description("Mark a team as blocked and kill all members").action(async(name)=>{try{await setTeamStatus(name,"blocked"),await killTeamMembers(name),console.log(`Team "${name}" marked as blocked. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}async function handleTeamCreate(name,options){if(options.wish){let resolvedRepo=resolve6(options.repo),wishPath=join35(resolvedRepo,".genie","wishes",options.wish,"WISH.md");if(!existsSync22(wishPath)){let cwdWishDir=join35(process.cwd(),".genie","wishes",options.wish),cwdWishPath=join35(cwdWishDir,"WISH.md");if(existsSync22(cwdWishPath)){let destDir=join35(resolvedRepo,".genie","wishes",options.wish);await mkdir11(destDir,{recursive:!0}),await cp(cwdWishDir,destDir,{recursive:!0}),console.log(`Wish: copied ${options.wish}/WISH.md to repo`)}else console.error(`Error: Wish not found at ${wishPath}`),process.exit(1)}}let config=await createTeam(name,options.repo,options.branch);if(options.session)config.tmuxSessionName=options.session,await updateTeamConfig(name,config);if(console.log(`Team "${config.name}" created.`),console.log(` Worktree: ${config.worktreePath}`),console.log(` Branch: ${config.name} (from ${config.baseBranch})`),config.tmuxSessionName)console.log(` Session: ${config.tmuxSessionName}`);if(config.nativeTeamsEnabled)console.log(" Native teams: enabled");if(options.wish)await spawnLeaderWithWish(config,options.wish,options.repo,options.session)}async function spawnLeaderWithWish(config,slug,repoPath,sessionOverride){let{handleWorkerSpawn:handleWorkerSpawn2}=await Promise.resolve().then(() => (init_agents(),exports_agents)),{getCurrentSessionName:getCurrentSessionName2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux)),resolvedRepo=resolve6(repoPath),tmuxSession=sessionOverride??await getCurrentSessionName2(config.name)??config.name;config.tmuxSessionName=tmuxSession,await updateTeamConfig(config.name,config);let sourceWishPath=join35(resolvedRepo,".genie","wishes",slug,"WISH.md");if(!existsSync22(sourceWishPath))console.error(`Error: Wish not found at ${sourceWishPath}`),process.exit(1);let destWishDir=join35(config.worktreePath,".genie","wishes",slug);await mkdir11(destWishDir,{recursive:!0});let destWishPath=join35(destWishDir,"WISH.md");await copyFile2(sourceWishPath,destWishPath),console.log(` Wish: copied ${slug}/WISH.md into worktree`);let standardTeam=["team-lead","engineer","reviewer","qa","fix"];for(let role of standardTeam)await hireAgent(config.name,role);console.log(` Team: hired ${standardTeam.join(", ")}`);let members=standardTeam.filter((r)=>r!=="team-lead").join(", "),kickoffPrompt=`Your team is "${config.name}". Repo: ${config.repo}. Branch: ${config.name}. Worktree: ${config.worktreePath}. Wish slug: ${slug}. Your team members are: ${members} (already hired \u2014 genie work will spawn them automatically). Read the wish at .genie/wishes/${slug}/WISH.md and execute the full lifecycle autonomously.`;await handleWorkerSpawn2("team-lead",{provider:"claude",team:config.name,cwd:config.worktreePath,session:tmuxSession,initialPrompt:kickoffPrompt});let result=await(await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router))).sendMessage(config.worktreePath,"cli","team-lead",kickoffPrompt);if(!result.delivered)console.warn(`\u26A0 Backup delivery to team-lead failed: ${result.reason??"unknown"}`);console.log(" Leader: spawned and working")}async function autoDetectTeam(){let envTeam=process.env.GENIE_TEAM;if(envTeam)return envTeam;let teams=await listTeams2();if(teams.length===1)return teams[0].name;return null}async function printMembers(name,json2){let members=await listMembers(name);if(members===null)console.error(`Team "${name}" not found.`),process.exit(1);if(json2){console.log(JSON.stringify(members,null,2));return}if(members.length===0){console.log(`Team "${name}" has no members. Hire agents with: genie team hire <agent> --team ${name}`);return}console.log(""),console.log(`MEMBERS of "${name}"`),console.log("-".repeat(60));for(let m of members)console.log(` ${m}`);console.log("")}async function printTeams(json2){let teams=await listTeams2();if(json2){console.log(JSON.stringify(teams,null,2));return}if(teams.length===0){console.log("No teams found. Create one with: genie team create <name> --repo <path>");return}console.log(""),console.log("TEAMS"),console.log("-".repeat(60));for(let t of teams)printTeamSummary(t);console.log("")}function printTeamSummary(t){let status=t.status??"in_progress";console.log(` ${t.name} [${status}]`),console.log(` Repo: ${t.repo}`),console.log(` Branch: ${t.name} (from ${t.baseBranch})`),console.log(` Worktree: ${t.worktreePath}`),console.log(` Members: ${t.members.length}`)}var _taskService7;async function getTaskService7(){if(!_taskService7)_taskService7=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService7}function padRight10(str3,len){return str3.length>=len?str3:str3+" ".repeat(len-str3.length)}function printTypeTable(types3){console.log(` ${padRight10("ID",20)} ${padRight10("NAME",30)} ${padRight10("STAGES",8)} BUILTIN`),console.log(` ${"\u2500".repeat(70)}`);for(let t of types3){let stageCount=Array.isArray(t.stages)?t.stages.length:0,builtin=t.isBuiltin?"yes":"no";console.log(` ${padRight10(t.id,20)} ${padRight10(t.name,30)} ${padRight10(String(stageCount),8)} ${builtin}`)}console.log(`
1233
+ Messages:`);for(let msg of messages2){let time=formatTimestamp3(msg.createdAt),reply=msg.replyToId?` (reply to #${msg.replyToId})`:"";console.log(` [${time}] ${msg.senderId}: ${msg.body}${reply}`)}}}async function printTaskDetail(task){printTaskFields(task),await printTaskRelations(task),await printTaskMessages(task),console.log("")}async function handleTaskCreate(title,options){let ts=await getTaskService6(),actor=currentActor2(),repoPath,projectId;if(options.project){let project=await ts.getProjectByName(options.project);if(!project)project=await ts.createProject({name:options.project});projectId=project.id,repoPath=project.repoPath??void 0}let parentId;if(options.parent){if(parentId=await ts.resolveTaskId(options.parent,repoPath)??void 0,!parentId)console.error(`Error: Parent task not found: ${options.parent}`),process.exit(1)}let task=await ts.createTask({title,typeId:options.type,priority:options.priority,dueDate:options.due,startDate:options.start,parentId,description:options.description,estimatedEffort:options.effort},repoPath,projectId);if(await ts.assignTask(task.id,actor,"creator",{},task.repoPath),options.assign)await ts.assignTask(task.id,localActor2(options.assign),"assignee",{},task.repoPath);if(options.tags){let tagIds=options.tags.split(",").map((t)=>t.trim());await ts.tagTask(task.id,tagIds,actor,task.repoPath)}if(options.comment)await ts.commentOnTask(task.id,actor,options.comment,task.repoPath);if(console.log(`Created task #${task.seq}: ${task.title}`),console.log(` ID: ${task.id}`),console.log(` Stage: ${task.stage} | Priority: ${task.priority}`),options.due)console.log(` Due: ${options.due}`)}function registerTaskCommands(program2){let task=program2.command("task").description("Task lifecycle management");task.command("create <title>").description("Create a new task").option("--type <type>","Task type","software").option("--priority <priority>","Priority: urgent, high, normal, low","normal").option("--due <date>","Due date (YYYY-MM-DD)").option("--start <date>","Start date (YYYY-MM-DD)").option("--tags <tags>","Comma-separated tag IDs").option("--parent <id>","Parent task ID or #seq").option("--assign <name>","Assign to local actor").option("--description <text>","Task description").option("--effort <effort>",'Estimated effort (e.g., "2h", "3 points")').option("--comment <msg>","Initial comment on the task").option("--project <name>","Create task in a specific project (overrides CWD)").action(async(title,options)=>{try{await handleTaskCreate(title,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("list").description("List tasks with filters").option("--stage <stage>","Filter by stage").option("--type <type>","Filter by type").option("--status <status>","Filter by status").option("--priority <priority>","Filter by priority").option("--release <release>","Filter by release").option("--due-before <date>","Filter by due date").option("--mine","Show only tasks assigned to me").option("--project <name>","Show tasks for a specific project").option("--all","Show tasks from ALL projects").option("--json","Output as JSON").action(async(options)=>{try{let ts=await getTaskService6(),filters={stage:options.stage,typeId:options.type,status:options.status,priority:options.priority,releaseId:options.release,dueBefore:options.dueBefore,projectName:options.project,allProjects:options.all},tasks;if(options.mine)tasks=await ts.listTasksForActor(currentActor2(),filters);else tasks=await ts.listTasks(filters);if(options.json){console.log(JSON.stringify(tasks,null,2));return}printTaskList(tasks,options.all)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("show <id>").description("Show task detail (accepts task-id or #seq)").option("--json","Output as JSON").action(async(id,options)=>{try{let t=await(await getTaskService6()).getTask(id);if(!t)console.error(`Error: Task not found: ${id}`),process.exit(1);if(options.json){console.log(JSON.stringify(t,null,2));return}await printTaskDetail(t)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("move <id>").description("Move task to a new stage").requiredOption("--to <stage>","Target stage").option("--comment <msg>","Comment on the move").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.moveTask(id,options.to,actor,options.comment);console.log(`Moved task #${t.seq} to stage "${t.stage}".`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("assign <id>").description("Assign an actor to a task").requiredOption("--to <name>","Actor name").option("--role <role>","Actor role","assignee").option("--comment <msg>","Comment on the assignment").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2();if(await ts.assignTask(id,localActor2(options.to),options.role,{}),options.comment)await ts.commentOnTask(id,actor,options.comment);console.log(`Assigned "${options.to}" as ${options.role??"assignee"} on task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("tag <id> <tags...>").description("Add tags to a task").action(async(id,tags)=>{try{await(await getTaskService6()).tagTask(id,tags,currentActor2()),console.log(`Tagged task ${id} with: ${tags.join(", ")}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("comment <id> <message>").description("Add a comment to a task").option("--reply-to <msgId>","Reply to a specific message ID").action(async(id,message,options)=>{try{let ts=await getTaskService6(),replyTo=options.replyTo?Number(options.replyTo):void 0,msg=await ts.commentOnTask(id,currentActor2(),message,void 0,replyTo);console.log(`Comment #${msg.id} added to task ${id}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("block <id>").description("Mark task as blocked").requiredOption("--reason <reason>","Reason for blocking").option("--comment <msg>","Additional comment").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.blockTask(id,options.reason,actor,options.comment);console.log(`Task #${t.seq} blocked: ${options.reason}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unblock <id>").description("Unblock a task").option("--comment <msg>","Comment on unblock").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.unblockTask(id,actor,options.comment);console.log(`Task #${t.seq} unblocked.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("done <id>").description("Mark task as done").option("--comment <msg>","Comment on completion").action(async(id,options)=>{try{let ts=await getTaskService6(),actor=currentActor2(),t=await ts.markDone(id,actor,options.comment);console.log(`Task #${t.seq} marked as done.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("checkout <id>").description("Atomically claim a task for execution").action(async(id)=>{try{let ts=await getTaskService6(),runId=getRunId(),t=await ts.checkoutTask(id,runId);console.log(`Checked out task #${t.seq} for run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("release <id>").description("Release task checkout claim").action(async(id)=>{try{let ts=await getTaskService6(),runId=getRunId(),t=await ts.releaseTask(id,runId);console.log(`Released task #${t.seq} from run: ${runId}`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("unlock <id>").description("Force-release a stale checkout (admin override)").action(async(id)=>{try{let t=await(await getTaskService6()).forceUnlockTask(id);console.log(`Force-unlocked task #${t.seq}.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),task.command("dep <id>").description("Manage task dependencies").option("--depends-on <id2>","This task depends on id2").option("--blocks <id2>","This task blocks id2").option("--relates-to <id2>","This task relates to id2").option("--remove <id2>","Remove dependency on id2").action(async(id,options)=>{try{let ts=await getTaskService6();if(options.remove){if(await ts.removeDependency(id,options.remove))console.log(`Removed dependency between ${id} and ${options.remove}.`);else console.log("No dependency found to remove.");return}if(options.dependsOn)await ts.addDependency(id,options.dependsOn,"depends_on"),console.log(`${id} now depends on ${options.dependsOn}.`);if(options.blocks)await ts.addDependency(id,options.blocks,"blocks"),console.log(`${id} now blocks ${options.blocks}.`);if(options.relatesTo)await ts.addDependency(id,options.relatesTo,"relates_to"),console.log(`${id} now relates to ${options.relatesTo}.`);if(!options.dependsOn&&!options.blocks&&!options.relatesTo)console.error("Error: Specify --depends-on, --blocks, --relates-to, or --remove."),process.exit(1)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}init_team_manager();import{existsSync as existsSync22}from"fs";import{copyFile as copyFile2,cp,mkdir as mkdir11}from"fs/promises";import{join as join35,resolve as resolve6}from"path";function registerTeamNamespace(program2){let team=program2.command("team").description("Team lifecycle management");team.command("create <name>").description("Create a new team with a git worktree").requiredOption("--repo <path>","Path to the git repository").option("--branch <branch>","Base branch to create from","dev").option("--wish <slug>","Wish slug \u2014 auto-spawns a task leader with wish context").option("--session <name>","Tmux session name (avoids session explosion on parallel creates)").action(async(name,options)=>{try{await handleTeamCreate(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("hire <agent>").description('Add an agent to a team ("council" hires all 10 council members)').option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);let added=await hireAgent(teamName,agent);if(added.length===0)console.log(`Agent "${agent}" is already a member of "${teamName}".`);else if(agent==="council"){console.log(`Hired ${added.length} council members to "${teamName}":`);for(let name of added)console.log(` + ${name}`)}else console.log(`Hired "${agent}" to team "${teamName}".`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("fire <agent>").description("Remove an agent from a team").option("--team <name>","Team name (auto-detects from leader context if omitted)").action(async(agent,options)=>{try{let teamName=options.team??await autoDetectTeam();if(!teamName)console.error("Error: Could not detect team. Use --team <name> to specify."),process.exit(1);if(await fireAgent(teamName,agent))console.log(`Fired "${agent}" from team "${teamName}".`);else console.error(`Agent "${agent}" is not a member of "${teamName}".`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("ls [name]").alias("list").description("List teams or members of a team").option("--json","Output as JSON").action(async(name,options)=>{try{if(name)await printMembers(name,options.json);else await printTeams(options.json)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("disband <name>").description("Disband a team: kill members, remove worktree, delete config").action(async(name)=>{try{if(await disbandTeam(name))console.log(`Team "${name}" disbanded.`);else console.error(`Team "${name}" not found.`),process.exit(1)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("done <name>").description("Mark a team as done and kill all members").action(async(name)=>{try{await setTeamStatus(name,"done"),await killTeamMembers(name),console.log(`Team "${name}" marked as done. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}),team.command("blocked <name>").description("Mark a team as blocked and kill all members").action(async(name)=>{try{await setTeamStatus(name,"blocked"),await killTeamMembers(name),console.log(`Team "${name}" marked as blocked. All members killed.`)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}})}async function handleTeamCreate(name,options){if(options.wish){let resolvedRepo=resolve6(options.repo),wishPath=join35(resolvedRepo,".genie","wishes",options.wish,"WISH.md");if(!existsSync22(wishPath)){let cwdWishDir=join35(process.cwd(),".genie","wishes",options.wish),cwdWishPath=join35(cwdWishDir,"WISH.md");if(existsSync22(cwdWishPath)){let destDir=join35(resolvedRepo,".genie","wishes",options.wish);await mkdir11(destDir,{recursive:!0}),await cp(cwdWishDir,destDir,{recursive:!0}),console.log(`Wish: copied ${options.wish}/WISH.md to repo`)}else console.error(`Error: Wish not found at ${wishPath}`),process.exit(1)}}let config=await createTeam(name,options.repo,options.branch),needsUpdate=!1;if(options.wish)config.wishSlug=options.wish,needsUpdate=!0;if(options.session)config.tmuxSessionName=options.session,needsUpdate=!0;if(needsUpdate)await updateTeamConfig(name,config);if(console.log(`Team "${config.name}" created.`),console.log(` Worktree: ${config.worktreePath}`),console.log(` Branch: ${config.name} (from ${config.baseBranch})`),config.tmuxSessionName)console.log(` Session: ${config.tmuxSessionName}`);if(config.nativeTeamsEnabled)console.log(" Native teams: enabled");if(options.wish)await spawnLeaderWithWish(config,options.wish,options.repo,options.session)}async function spawnLeaderWithWish(config,slug,repoPath,sessionOverride){let{handleWorkerSpawn:handleWorkerSpawn2}=await Promise.resolve().then(() => (init_agents(),exports_agents)),{getCurrentSessionName:getCurrentSessionName2}=await Promise.resolve().then(() => (init_tmux(),exports_tmux)),resolvedRepo=resolve6(repoPath),tmuxSession=sessionOverride??await getCurrentSessionName2(config.name)??config.name;config.tmuxSessionName=tmuxSession,await updateTeamConfig(config.name,config);let sourceWishPath=join35(resolvedRepo,".genie","wishes",slug,"WISH.md");if(!existsSync22(sourceWishPath))console.error(`Error: Wish not found at ${sourceWishPath}`),process.exit(1);let destWishDir=join35(config.worktreePath,".genie","wishes",slug);await mkdir11(destWishDir,{recursive:!0});let destWishPath=join35(destWishDir,"WISH.md");await copyFile2(sourceWishPath,destWishPath),console.log(` Wish: copied ${slug}/WISH.md into worktree`);let standardTeam=["team-lead","engineer","reviewer","qa","fix"];for(let role of standardTeam)await hireAgent(config.name,role);console.log(` Team: hired ${standardTeam.join(", ")}`);let members=standardTeam.filter((r)=>r!=="team-lead").join(", "),kickoffPrompt=`Your team is "${config.name}". Repo: ${config.repo}. Branch: ${config.name}. Worktree: ${config.worktreePath}. Wish slug: ${slug}. Your team members are: ${members} (already hired \u2014 genie work will spawn them automatically). Read the wish at .genie/wishes/${slug}/WISH.md and execute the full lifecycle autonomously.`;await handleWorkerSpawn2("team-lead",{provider:"claude",team:config.name,cwd:config.worktreePath,session:tmuxSession,initialPrompt:kickoffPrompt});let result=await(await Promise.resolve().then(() => (init_protocol_router(),exports_protocol_router))).sendMessage(config.worktreePath,"cli","team-lead",kickoffPrompt);if(!result.delivered)console.warn(`\u26A0 Backup delivery to team-lead failed: ${result.reason??"unknown"}`);console.log(" Leader: spawned and working")}async function autoDetectTeam(){let envTeam=process.env.GENIE_TEAM;if(envTeam)return envTeam;let teams=await listTeams2();if(teams.length===1)return teams[0].name;return null}async function printMembers(name,json2){let members=await listMembers(name);if(members===null)console.error(`Team "${name}" not found.`),process.exit(1);if(json2){console.log(JSON.stringify(members,null,2));return}if(members.length===0){console.log(`Team "${name}" has no members. Hire agents with: genie team hire <agent> --team ${name}`);return}console.log(""),console.log(`MEMBERS of "${name}"`),console.log("-".repeat(60));for(let m of members)console.log(` ${m}`);console.log("")}async function printTeams(json2){let teams=await listTeams2();if(json2){console.log(JSON.stringify(teams,null,2));return}if(teams.length===0){console.log("No teams found. Create one with: genie team create <name> --repo <path>");return}console.log(""),console.log("TEAMS"),console.log("-".repeat(60));for(let t of teams)printTeamSummary(t);console.log("")}function printTeamSummary(t){let status=t.status??"in_progress";console.log(` ${t.name} [${status}]`),console.log(` Repo: ${t.repo}`),console.log(` Branch: ${t.name} (from ${t.baseBranch})`),console.log(` Worktree: ${t.worktreePath}`),console.log(` Members: ${t.members.length}`)}var _taskService7;async function getTaskService7(){if(!_taskService7)_taskService7=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService7}function padRight10(str3,len){return str3.length>=len?str3:str3+" ".repeat(len-str3.length)}function printTypeTable(types3){console.log(` ${padRight10("ID",20)} ${padRight10("NAME",30)} ${padRight10("STAGES",8)} BUILTIN`),console.log(` ${"\u2500".repeat(70)}`);for(let t of types3){let stageCount=Array.isArray(t.stages)?t.stages.length:0,builtin=t.isBuiltin?"yes":"no";console.log(` ${padRight10(t.id,20)} ${padRight10(t.name,30)} ${padRight10(String(stageCount),8)} ${builtin}`)}console.log(`
1226
1234
  ${types3.length} type${types3.length===1?"":"s"}`)}function printTypePipeline(t){if(console.log(`
1227
1235
  Type: ${t.name} (${t.id})`),t.description)console.log(`Description: ${t.description}`);if(t.icon)console.log(`Icon: ${t.icon}`);console.log(`Built-in: ${t.isBuiltin?"yes":"no"}`),console.log("\u2500".repeat(60)),console.log(`
1228
1236
  Stage Pipeline:`);let stages=t.stages;for(let i2=0;i2<stages.length;i2++){let s=stages[i2],arrow=i2<stages.length-1?" \u2192":"",gate=s.gate?` [gate: ${s.gate}]`:"",action=s.action?` (action: ${s.action})`:"",auto=s.auto_advance?" [auto]":"";console.log(` ${i2+1}. ${s.label??s.name}${gate}${action}${auto}${arrow}`)}console.log("")}async function handleTypeList(options){let types3=await(await getTaskService7()).listTypes();if(options.json){console.log(JSON.stringify(types3,null,2));return}printTypeTable(types3)}async function handleTypeShow(id,options){let t=await(await getTaskService7()).getType(id);if(!t)console.error(`Error: Type not found: ${id}`),process.exit(1);if(options.json){console.log(JSON.stringify(t,null,2));return}printTypePipeline(t)}async function handleTypeCreate(name,options){let ts=await getTaskService7(),stages;try{if(stages=JSON.parse(options.stages),!Array.isArray(stages))throw Error("Stages must be a JSON array")}catch(err){console.error(`Error: Invalid stages JSON. ${err instanceof Error?err.message:String(err)}`),process.exit(1)}for(let s of stages)if(typeof s!=="object"||s===null||!("name"in s))console.error('Error: Each stage must have at least a "name" field.'),process.exit(1);let id=name.toLowerCase().replace(/\s+/g,"-"),t=await ts.createType({id,name,description:options.description,icon:options.icon,stages});console.log(`Created type "${t.name}" (${t.id}) with ${stages.length} stages.`)}function registerTypeCommands(program2){let type2=program2.command("type").description("Task type management");type2.command("list").description("List all task types").option("--json","Output as JSON").action(async(options)=>{try{await handleTypeList(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),type2.command("show <id>").description("Show task type detail with stage pipeline").option("--json","Output as JSON").action(async(id,options)=>{try{await handleTypeShow(id,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),type2.command("create <name>").description("Create a custom task type").requiredOption("--stages <json>","Stages JSON array").option("--description <text>","Type description").option("--icon <icon>","Type icon").action(async(name,options)=>{try{await handleTypeCreate(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}try{let{execSync:execSyncStartup}=__require("child_process");if(execSyncStartup("git config core.bare",{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()==="true")execSyncStartup("git config core.bare false",{stdio:["pipe","pipe","pipe"]})}catch{}var program2=new Command;program2.name("genie").description("Genie CLI - AI-assisted development").version(VERSION);async function startNamedSession(name){let{buildTeamLeadCommand:buildTeamLeadCommand2,sessionExists:sessionExists2}=await Promise.resolve().then(() => (init_team_lead_command(),exports_team_lead_command)),{getAgentsFilePath:getAgentsFilePath2}=await Promise.resolve().then(() => (init_session(),exports_session)),systemPromptFile=getAgentsFilePath2(),hasPriorSession=sessionExists2(name),cmd=buildTeamLeadCommand2(name,{systemPromptFile:systemPromptFile??void 0,continueName:hasPriorSession?name:void 0});console.log(hasPriorSession?`Resuming session: ${name}`:`Starting new session: ${name}`);let{spawnSync:spawnSync2}=await import("child_process"),result=spawnSync2("sh",["-c",cmd],{stdio:"inherit"});if(result.status)process.exit(result.status)}program2.command("setup").description("Configure genie settings").option("--quick","Accept all defaults").option("--shortcuts","Only configure keyboard shortcuts").option("--codex","Only configure Codex integration").option("--terminal","Only configure terminal defaults").option("--session","Only configure session settings").option("--reset","Reset configuration to defaults").option("--show","Show current configuration").action(async(options)=>{await setupCommand(options)});program2.command("doctor").description("Run diagnostic checks on genie installation").action(doctorCommand);program2.command("update").description("Update Genie CLI to the latest version").option("--next","Switch to dev builds (npm @next tag)").option("--stable","Switch to stable releases (npm @latest tag)").action(updateCommand);program2.command("uninstall").description("Remove Genie CLI and clean up hooks").action(uninstallCommand);var shortcuts=program2.command("shortcuts").description("Manage tmux keyboard shortcuts");shortcuts.action(shortcutsShowCommand);shortcuts.command("show").description("Show available shortcuts and installation status").action(shortcutsShowCommand);shortcuts.command("install").description("Install shortcuts to config files (~/.tmux.conf, shell rc)").action(shortcutsInstallCommand);shortcuts.command("uninstall").description("Remove shortcuts from config files").action(shortcutsUninstallCommand);registerTeamNamespace(program2);registerDirNamespace(program2);registerAgentNamespace(program2);registerSendInboxCommands(program2);registerStateCommands(program2);registerDispatchCommands(program2);registerHookNamespace(program2);registerDbCommands(program2);registerScheduleCommands(program2);registerDaemonCommands(program2);registerTaskCommands(program2);registerTypeCommands(program2);registerTagCommands(program2);registerReleaseCommands(program2);registerProjectCommands(program2);registerNotifyCommands(program2);program2.command("spawn <name>").description("Spawn a new agent by name (resolves from directory or built-ins)").option("--provider <provider>","Provider: claude or codex","claude").option("--team <team>","Team name",process.env.GENIE_TEAM??"genie").option("--model <model>","Model override (e.g., sonnet, opus)").option("--skill <skill>","Skill to load (optional)").option("--layout <layout>","Layout mode: mosaic (default) or vertical").option("--color <color>","Teammate pane border color").option("--plan-mode","Start teammate in plan mode").option("--permission-mode <mode>","Permission mode (e.g., acceptEdits)").option("--extra-args <args...>","Extra CLI args forwarded to provider").option("--cwd <path>","Working directory for the agent (overrides directory entry)").option("--session <session>","Tmux session name to spawn into").option("--no-auto-resume","Disable auto-resume on pane death").action(async(name,options)=>{try{await handleWorkerSpawn(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});program2.command("kill <name>").description("Force kill an agent by name").action(async(name)=>{try{await handleWorkerKill(name)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});program2.command("stop <name>").description("Stop an agent (preserves session for resume)").action(async(name)=>{try{await handleWorkerStop(name)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});program2.command("resume [name]").description("Resume a suspended/failed agent with its Claude session").option("--all","Resume all eligible agents").action(async(name,options)=>{try{await handleWorkerResume(name,options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});program2.command("history <name>").description("Show compressed session history for an agent").option("--full","Show full conversation without compression").option("--since <n>","Show last N user/assistant exchanges",Number.parseInt).option("--last <n>","Show last N transcript entries",Number.parseInt).option("--type <role>","Filter by role (user, assistant, tool_call)").option("--after <timestamp>","Only entries after ISO timestamp").option("--json","Output as JSON").option("--ndjson","Output as newline-delimited JSON (pipeable to jq)").option("--raw","Output raw JSONL entries").option("--log-file <path>","Direct path to log file (for testing)").action(async(name,options)=>{await historyCommand(name,options)});program2.command("log [agent]").description("Unified observability feed \u2014 aggregates transcript, DMs, team chat").option("--team <name>","Show interleaved feed for all agents in a team").option("--type <kind>","Filter by event kind (transcript, message, tool_call, state, system)").option("--since <timestamp>","Only events after ISO timestamp").option("--last <n>","Show last N events",Number.parseInt).option("--ndjson","Output as newline-delimited JSON (pipeable to jq)").option("--json","Output as pretty JSON").option("-f, --follow","Follow mode \u2014 real-time streaming").action(async(agent,options)=>{await logCommand(agent,options)});var qaCmd=program2.command("qa").description("QA \u2014 self-testing system for genie CLI");qaCmd.command("run [target]",{isDefault:!0}).description("Run QA specs (all, a domain, or a single spec)").option("--timeout <seconds>","Max seconds per spec",(v)=>Number(v),60).option("--parallel <n>","Max specs to run in parallel",(v)=>Number(v),5).option("--verbose","Show all collected events").option("--ndjson","Machine-readable NDJSON output").action(async(target,options)=>{await qaCommand(target,options)});qaCmd.command("status").description("Show QA dashboard with last results per spec").option("--json","Output as JSON").action(async(options)=>{await qaStatusCommand(options)});qaCmd.command("history").description("Show recent QA runs").action(async()=>{await qaHistoryCommand()});program2.command("qa-report <json>").description("Publish QA result via NATS (called by QA team-lead)").action(async(json2)=>{let team=process.env.GENIE_TEAM;if(!team)console.error("Error: GENIE_TEAM not set. This command must be run by a QA team-lead agent."),process.exit(1);try{let{publish:publish2,close:close2}=await Promise.resolve().then(() => (init_nats_client(),exports_nats_client)),data=JSON.parse(json2);await publish2(`genie.qa.${team}.result`,data),await close2(),console.log(`QA result published to genie.qa.${team}.result`)}catch(err){console.error(`Failed to publish QA result: ${err}`),process.exit(1)}});program2.command("read <name>").description("Read terminal output from an agent pane").option("-n, --lines <number>","Number of lines to read").option("--from <line>","Start line").option("--to <line>","End line").option("--range <range>",'Line range (e.g., "10-20")').option("--search <text>","Search for text").option("--grep <pattern>","Grep for pattern").option("-f, --follow","Follow mode (like tail -f)").option("--all","Show all output").option("-r, --reverse","Reverse order").option("--json","Output as JSON").action(async(name,options)=>{await readSessionLogs2(name,options)});program2.command("answer <name> <choice>").description('Answer a question for an agent (use "text:..." for text input)').action(async(name,choice)=>{await answerQuestion(name,choice)});program2.command("ls").description("List registered agents with runtime status").option("--json","Output as JSON").action(async(options)=>{try{await handleLsCommand(options)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}});var args=process.argv.slice(2);if(args.length===0||args.every((a)=>a==="--reset")){let{sessionCommand:sessionCommand2}=await Promise.resolve().then(() => (init_session(),exports_session));await sessionCommand2({reset:args.includes("--reset")}),process.exit(0)}var sessionIdx=args.indexOf("--session");if(sessionIdx!==-1&&sessionIdx+1<args.length){let sessionName=args[sessionIdx+1];if(!args.filter((_,i2)=>i2!==sessionIdx&&i2!==sessionIdx+1).some((a)=>!a.startsWith("-")))try{await startNamedSession(sessionName),process.exit(0)}catch(err){console.error(`Error: ${err instanceof Error?err.message:err}`),process.exit(1)}else program2.parse()}else program2.parse();
@@ -2,7 +2,7 @@
2
2
  "id": "genie",
3
3
  "name": "Genie",
4
4
  "description": "Skills, agents, and hooks for the Genie CLI terminal orchestration toolkit",
5
- "version": "4.260325.3",
5
+ "version": "4.260325.5",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260325.3",
3
+ "version": "4.260325.5",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260325.3",
3
+ "version": "4.260325.5",
4
4
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
5
5
  "author": {
6
6
  "name": "Namastex Labs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260325.3",
3
+ "version": "4.260325.5",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",
package/src/lib/db.ts CHANGED
@@ -318,6 +318,9 @@ function markMigrationsDone(): void {
318
318
  /**
319
319
  * Get a postgres.js connection. Lazy singleton — calls ensurePgserve() on first use.
320
320
  * Returns a postgres.js sql tagged template client.
321
+ *
322
+ * When GENIE_TEST_SCHEMA is set, all connections use that schema in their search_path.
323
+ * This isolates test data from production tables.
321
324
  */
322
325
  export async function getConnection() {
323
326
  if (sqlClient) return sqlClient;
@@ -325,6 +328,7 @@ export async function getConnection() {
325
328
  const port = await ensurePgserve();
326
329
  const postgres = (await import('postgres')).default;
327
330
 
331
+ const testSchema = process.env.GENIE_TEST_SCHEMA;
328
332
  sqlClient = postgres({
329
333
  host: DEFAULT_HOST,
330
334
  port,
@@ -334,6 +338,7 @@ export async function getConnection() {
334
338
  max: 10,
335
339
  idle_timeout: 1,
336
340
  connect_timeout: 5,
341
+ ...(testSchema ? { connection: { search_path: `${testSchema}, public` } } : {}),
337
342
  });
338
343
 
339
344
  // Only run migrations if not yet applied for this version
@@ -345,6 +350,17 @@ export async function getConnection() {
345
350
  return sqlClient;
346
351
  }
347
352
 
353
+ /**
354
+ * Reset the connection singleton. Next call to getConnection() creates a fresh client.
355
+ * Used by test helpers to switch schemas between test runs.
356
+ */
357
+ export async function resetConnection(): Promise<void> {
358
+ if (sqlClient) {
359
+ await sqlClient.end({ timeout: 5 });
360
+ sqlClient = null;
361
+ }
362
+ }
363
+
348
364
  /**
349
365
  * Non-throwing health check. Returns true if pgserve is reachable and responds to queries.
350
366
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
9
- import { getConnection, shutdown } from './db.js';
9
+ import { getConnection } from './db.js';
10
10
  import {
11
11
  type Actor,
12
12
  addDependency,
@@ -63,6 +63,7 @@ import {
63
63
  updateMessage,
64
64
  updateTask,
65
65
  } from './task-service.js';
66
+ import { setupTestSchema } from './test-db.js';
66
67
 
67
68
  // Unique repo path per test run to avoid collisions
68
69
  const REPO = `/tmp/test-repo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
@@ -70,18 +71,15 @@ const actor: Actor = { actorType: 'local', actorId: 'test-user' };
70
71
  const actor2: Actor = { actorType: 'local', actorId: 'test-user-2' };
71
72
 
72
73
  let sql: Awaited<ReturnType<typeof getConnection>>;
74
+ let cleanupSchema: () => Promise<void>;
73
75
 
74
76
  beforeAll(async () => {
77
+ cleanupSchema = await setupTestSchema();
75
78
  sql = await getConnection();
76
79
  });
77
80
 
78
81
  afterAll(async () => {
79
- // Clean up test data
80
- if (sql) {
81
- await sql`DELETE FROM tasks WHERE repo_path = ${REPO}`;
82
- await sql`DELETE FROM tasks WHERE repo_path LIKE '/tmp/test-repo-%'`;
83
- }
84
- await shutdown();
82
+ await cleanupSchema();
85
83
  });
86
84
 
87
85
  // ============================================================================
@@ -52,6 +52,8 @@ export interface TeamConfig {
52
52
  nativeTeamsEnabled?: boolean;
53
53
  /** Tmux session name used by this team — single source of truth for all workers. */
54
54
  tmuxSessionName?: string;
55
+ /** Wish slug this team is working on (set via --wish). */
56
+ wishSlug?: string;
55
57
  }
56
58
 
57
59
  // ============================================================================
@@ -338,6 +340,19 @@ export async function disbandTeam(teamName: string): Promise<boolean> {
338
340
  }
339
341
  }
340
342
 
343
+ // Reset in-progress wish groups so re-dispatch works cleanly
344
+ if (config.wishSlug) {
345
+ try {
346
+ const wishState = await import('./wish-state.js');
347
+ const resetCount = await wishState.resetInProgressGroups(config.wishSlug, config.repo);
348
+ if (resetCount > 0) {
349
+ console.log(` Reset ${resetCount} in-progress group(s) for wish "${config.wishSlug}"`);
350
+ }
351
+ } catch {
352
+ // Best-effort — DB may be unavailable
353
+ }
354
+ }
355
+
341
356
  // Remove shared clone directory
342
357
  if (config.worktreePath && existsSync(config.worktreePath)) {
343
358
  try {
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Test Database Helpers — PG schema isolation for tests.
3
+ *
4
+ * Each test file gets its own PG schema so test data never touches
5
+ * the production `public` schema. Schemas are created in beforeAll
6
+ * and dropped in afterAll — zero artifacts after `bun test`.
7
+ *
8
+ * Usage:
9
+ * import { setupTestSchema, teardownTestSchema } from './test-db.js';
10
+ *
11
+ * let cleanup: () => Promise<void>;
12
+ * beforeAll(async () => { cleanup = await setupTestSchema(); });
13
+ * afterAll(async () => { await cleanup(); });
14
+ */
15
+
16
+ import { runMigrations } from './db-migrations.js';
17
+ import { ensurePgserve, resetConnection } from './db.js';
18
+
19
+ /**
20
+ * Create an isolated PG schema for this test file.
21
+ * Returns a cleanup function that drops the schema and resets the connection.
22
+ *
23
+ * How it works:
24
+ * 1. Gets a default connection (no schema override)
25
+ * 2. Creates a unique schema named `test_<pid>_<timestamp>`
26
+ * 3. Runs all migrations inside that schema
27
+ * 4. Resets the connection singleton
28
+ * 5. Sets GENIE_TEST_SCHEMA env var so getConnection() uses the test schema
29
+ *
30
+ * All subsequent getConnection() calls in this process will use the test schema.
31
+ */
32
+ export async function setupTestSchema(): Promise<() => Promise<void>> {
33
+ const schemaName = `test_${process.pid}_${Date.now()}`;
34
+
35
+ // Get a raw connection to create the schema
36
+ const port = await ensurePgserve();
37
+ const postgres = (await import('postgres')).default;
38
+ const adminSql = postgres({
39
+ host: '127.0.0.1',
40
+ port,
41
+ database: 'genie',
42
+ username: 'postgres',
43
+ password: 'postgres',
44
+ max: 2,
45
+ idle_timeout: 1,
46
+ connect_timeout: 5,
47
+ });
48
+
49
+ // Create test schema and run migrations inside it
50
+ await adminSql.unsafe(`CREATE SCHEMA IF NOT EXISTS "${schemaName}"`);
51
+ await adminSql.unsafe(`SET search_path TO "${schemaName}", public`);
52
+ await runMigrations(adminSql);
53
+ await adminSql.end({ timeout: 5 });
54
+
55
+ // Reset the singleton and set the env var so getConnection() picks up the schema
56
+ await resetConnection();
57
+ process.env.GENIE_TEST_SCHEMA = schemaName;
58
+
59
+ // Return cleanup function
60
+ return async () => {
61
+ // Reset connection before dropping schema
62
+ await resetConnection();
63
+
64
+ // Drop the test schema with a fresh admin connection
65
+ const cleanupSql = postgres({
66
+ host: '127.0.0.1',
67
+ port,
68
+ database: 'genie',
69
+ username: 'postgres',
70
+ password: 'postgres',
71
+ max: 2,
72
+ idle_timeout: 1,
73
+ connect_timeout: 5,
74
+ });
75
+
76
+ try {
77
+ await cleanupSql.unsafe(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`);
78
+ } finally {
79
+ await cleanupSql.end({ timeout: 5 });
80
+ }
81
+
82
+ // Clear env var
83
+ process.env.GENIE_TEST_SCHEMA = undefined;
84
+ };
85
+ }
@@ -10,7 +10,7 @@ import { execSync } from 'node:child_process';
10
10
  import { mkdtempSync, rmSync } from 'node:fs';
11
11
  import { tmpdir } from 'node:os';
12
12
  import { join } from 'node:path';
13
- import { getConnection, shutdown } from './db.js';
13
+ import { setupTestSchema } from './test-db.js';
14
14
  import {
15
15
  type GroupDefinition,
16
16
  completeGroup,
@@ -22,18 +22,20 @@ import {
22
22
  getState,
23
23
  isWishComplete,
24
24
  resetGroup,
25
+ resetInProgressGroups,
25
26
  resolveRepoPath,
26
27
  startGroup,
27
28
  } from './wish-state.js';
28
29
 
29
30
  let cwd: string;
31
+ let cleanupSchema: () => Promise<void>;
30
32
 
31
33
  beforeAll(async () => {
32
- await getConnection();
34
+ cleanupSchema = await setupTestSchema();
33
35
  });
34
36
 
35
37
  afterAll(async () => {
36
- await shutdown();
38
+ await cleanupSchema();
37
39
  });
38
40
 
39
41
  beforeEach(() => {
@@ -610,6 +612,53 @@ describe('isWishComplete', () => {
610
612
  });
611
613
  });
612
614
 
615
+ // ============================================================================
616
+ // resetInProgressGroups
617
+ // ============================================================================
618
+
619
+ describe('resetInProgressGroups', () => {
620
+ test('returns 0 for nonexistent wish', async () => {
621
+ expect(await resetInProgressGroups('nonexistent', cwd)).toBe(0);
622
+ });
623
+
624
+ test('resets all in_progress groups to ready', async () => {
625
+ const groups: GroupDefinition[] = [{ name: 'a' }, { name: 'b' }, { name: 'c' }];
626
+ await createState('reset-all', groups, cwd);
627
+ await startGroup('reset-all', 'a', 'agent-1', cwd);
628
+ await startGroup('reset-all', 'b', 'agent-2', cwd);
629
+
630
+ const count = await resetInProgressGroups('reset-all', cwd);
631
+ expect(count).toBe(2);
632
+
633
+ const state = await getState('reset-all', cwd);
634
+ expect(state?.groups.a.status).toBe('ready');
635
+ expect(state?.groups.a.assignee).toBeUndefined();
636
+ expect(state?.groups.b.status).toBe('ready');
637
+ expect(state?.groups.b.assignee).toBeUndefined();
638
+ expect(state?.groups.c.status).toBe('ready'); // was already ready
639
+ });
640
+
641
+ test('does not touch done groups', async () => {
642
+ await createState('reset-done', sampleGroups, cwd);
643
+ await startGroup('reset-done', '1', 'a', cwd);
644
+ await completeGroup('reset-done', '1', cwd);
645
+ await startGroup('reset-done', '2', 'b', cwd);
646
+
647
+ const count = await resetInProgressGroups('reset-done', cwd);
648
+ expect(count).toBe(1); // only group 2
649
+
650
+ const state = await getState('reset-done', cwd);
651
+ expect(state?.groups['1'].status).toBe('done');
652
+ expect(state?.groups['2'].status).toBe('ready');
653
+ });
654
+
655
+ test('returns 0 when no groups are in_progress', async () => {
656
+ await createState('reset-none', [{ name: '1' }], cwd);
657
+ const count = await resetInProgressGroups('reset-none', cwd);
658
+ expect(count).toBe(0);
659
+ });
660
+ });
661
+
613
662
  // ============================================================================
614
663
  // resolveRepoPath — worktree normalization
615
664
  // ============================================================================
@@ -573,3 +573,41 @@ export async function isWishComplete(slug: string, cwd?: string): Promise<boolea
573
573
  const groups = Object.values(state.groups);
574
574
  return groups.length > 0 && groups.every((g) => g.status === 'done');
575
575
  }
576
+
577
+ /**
578
+ * Reset all in_progress groups back to ready for a wish.
579
+ * Used during team disband to prevent stale state from blocking re-dispatch.
580
+ * Returns the number of groups that were reset.
581
+ */
582
+ export async function resetInProgressGroups(slug: string, cwd?: string): Promise<number> {
583
+ const sql = await getConnection();
584
+ const repoPath = resolveRepoPath(cwd);
585
+
586
+ const parent = await findParent(sql, slug, repoPath);
587
+ if (!parent) return 0;
588
+
589
+ const now = new Date();
590
+
591
+ // Find all in_progress children
592
+ const inProgress = await sql`
593
+ SELECT id FROM tasks
594
+ WHERE parent_id = ${parent.id as string} AND status = 'in_progress'
595
+ `;
596
+
597
+ if (inProgress.length === 0) return 0;
598
+
599
+ const ids = inProgress.map((r: Record<string, unknown>) => r.id as string);
600
+
601
+ // Reset to ready, clear started_at
602
+ await sql`
603
+ UPDATE tasks SET status = 'ready', started_at = NULL, updated_at = ${now}
604
+ WHERE id = ANY(${ids})
605
+ `;
606
+
607
+ // Remove assignees
608
+ await sql`
609
+ DELETE FROM task_actors WHERE task_id = ANY(${ids}) AND role = 'assignee'
610
+ `;
611
+
612
+ return ids.length;
613
+ }
@@ -7,18 +7,19 @@
7
7
 
8
8
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'bun:test';
9
9
  import type { Agent } from '../lib/agent-registry.js';
10
- import { getConnection, shutdown } from '../lib/db.js';
10
+ import { setupTestSchema } from '../lib/test-db.js';
11
11
  import * as wishState from '../lib/wish-state.js';
12
12
  import { buildResumeContext } from './agents.js';
13
13
 
14
14
  let cwd: string;
15
+ let cleanupSchema: () => Promise<void>;
15
16
 
16
17
  beforeAll(async () => {
17
- await getConnection();
18
+ cleanupSchema = await setupTestSchema();
18
19
  });
19
20
 
20
21
  afterAll(async () => {
21
- await shutdown();
22
+ await cleanupSchema();
22
23
  });
23
24
 
24
25
  beforeEach(() => {
@@ -12,12 +12,11 @@
12
12
  * 8. reviewCommand() — review with diff context
13
13
  */
14
14
 
15
- import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
15
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
16
16
  import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
17
17
  import { join } from 'node:path';
18
+ import { setupTestSchema } from '../lib/test-db.js';
18
19
  import * as wishState from '../lib/wish-state.js';
19
- import { parseRef } from './state.js';
20
-
21
20
  import {
22
21
  buildContextPrompt,
23
22
  detectWorkMode,
@@ -27,6 +26,17 @@ import {
27
26
  parseWishGroups,
28
27
  writeContextFile,
29
28
  } from './dispatch.js';
29
+ import { parseRef } from './state.js';
30
+
31
+ let cleanupSchema: () => Promise<void>;
32
+
33
+ beforeAll(async () => {
34
+ cleanupSchema = await setupTestSchema();
35
+ });
36
+
37
+ afterAll(async () => {
38
+ await cleanupSchema();
39
+ });
30
40
 
31
41
  // ============================================================================
32
42
  // Sample WISH.md content for testing
@@ -2,13 +2,24 @@
2
2
  * Tests for state commands — wave detection, push enforcement, pane auto-kill.
3
3
  */
4
4
 
5
- import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
5
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
6
6
  import { execSync } from 'node:child_process';
7
7
  import { mkdir, rm, writeFile } from 'node:fs/promises';
8
8
  import { join } from 'node:path';
9
+ import { setupTestSchema } from '../lib/test-db.js';
9
10
  import * as wishState from '../lib/wish-state.js';
10
11
  import { detectWaveCompletion, ensureWorkPushed, parseRef, resolveWishPath } from './state.js';
11
12
 
13
+ let cleanupSchema: () => Promise<void>;
14
+
15
+ beforeAll(async () => {
16
+ cleanupSchema = await setupTestSchema();
17
+ });
18
+
19
+ afterAll(async () => {
20
+ await cleanupSchema();
21
+ });
22
+
12
23
  // ============================================================================
13
24
  // Sample WISH.md with Execution Strategy for wave detection tests
14
25
  // ============================================================================
@@ -198,9 +198,17 @@ async function handleTeamCreate(
198
198
 
199
199
  const config = await teamManager.createTeam(name, options.repo, options.branch);
200
200
 
201
- // Store tmux session name in team config (prevents session explosion on parallel creates)
201
+ // Store wish slug and tmux session in team config
202
+ let needsUpdate = false;
203
+ if (options.wish) {
204
+ config.wishSlug = options.wish;
205
+ needsUpdate = true;
206
+ }
202
207
  if (options.session) {
203
208
  config.tmuxSessionName = options.session;
209
+ needsUpdate = true;
210
+ }
211
+ if (needsUpdate) {
204
212
  await teamManager.updateTeamConfig(name, config);
205
213
  }
206
214