obsidian-agent-fleet 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/package.json +1 -1
- package/plugin/main.js +156 -169
- package/plugin/manifest.json +2 -2
- package/plugin/styles.css +190 -221
package/plugin/main.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"use strict";var rl=Object.create;var $s=Object.defineProperty;var il=Object.getOwnPropertyDescriptor;var ol=Object.getOwnPropertyNames;var ll=Object.getPrototypeOf,cl=Object.prototype.hasOwnProperty;var Ve=(r,t)=>()=>(t||r((t={exports:{}}).exports,t),t.exports),dl=(r,t)=>{for(var e in t)$s(r,e,{get:t[e],enumerable:!0})},ar=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ol(t))!cl.call(r,n)&&n!==e&&$s(r,n,{get:()=>t[n],enumerable:!(s=il(t,n))||s.enumerable});return r};var Ye=(r,t,e)=>(e=r!=null?rl(ll(r)):{},ar(t||!r||!r.__esModule?$s(e,"default",{value:r,enumerable:!0}):e,r)),hl=r=>ar($s({},"__esModule",{value:!0}),r);var gt=Ve((Sp,Pi)=>{"use strict";var Ai=["nodebuffer","arraybuffer","fragments"],Ei=typeof Blob<"u";Ei&&Ai.push("blob");Pi.exports={BINARY_TYPES:Ai,CLOSE_TIMEOUT:3e4,EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",hasBlob:Ei,kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}}});var _s=Ve((Cp,xn)=>{"use strict";var{EMPTY_BUFFER:xc}=gt(),Ca=Buffer[Symbol.species];function Sc(r,t){if(r.length===0)return xc;if(r.length===1)return r[0];let e=Buffer.allocUnsafe(t),s=0;for(let n=0;n<r.length;n++){let a=r[n];e.set(a,s),s+=a.length}return s<t?new Ca(e.buffer,e.byteOffset,s):e}function Ri(r,t,e,s,n){for(let a=0;a<n;a++)e[s+a]=r[a]^t[a&3]}function Di(r,t){for(let e=0;e<r.length;e++)r[e]^=t[e&3]}function Cc(r){return r.length===r.buffer.byteLength?r.buffer:r.buffer.slice(r.byteOffset,r.byteOffset+r.length)}function Ta(r){if(Ta.readOnly=!0,Buffer.isBuffer(r))return r;let t;return r instanceof ArrayBuffer?t=new Ca(r):ArrayBuffer.isView(r)?t=new Ca(r.buffer,r.byteOffset,r.byteLength):(t=Buffer.from(r),Ta.readOnly=!1),t}xn.exports={concat:Sc,mask:Ri,toArrayBuffer:Cc,toBuffer:Ta,unmask:Di};if(!process.env.WS_NO_BUFFER_UTIL)try{let r=require("bufferutil");xn.exports.mask=function(t,e,s,n,a){a<48?Ri(t,e,s,n,a):r.mask(t,e,s,n,a)},xn.exports.unmask=function(t,e){t.length<32?Di(t,e):r.unmask(t,e)}}catch{}});var Li=Ve((Tp,Mi)=>{"use strict";var Ii=Symbol("kDone"),_a=Symbol("kRun"),Aa=class{constructor(t){this[Ii]=()=>{this.pending--,this[_a]()},this.concurrency=t||1/0,this.jobs=[],this.pending=0}add(t){this.jobs.push(t),this[_a]()}[_a](){if(this.pending!==this.concurrency&&this.jobs.length){let t=this.jobs.shift();this.pending++,t(this[Ii])}}};Mi.exports=Aa});var Qt=Ve((_p,Bi)=>{"use strict";var As=require("zlib"),Fi=_s(),Tc=Li(),{kStatusCode:Oi}=gt(),_c=Buffer[Symbol.species],Ac=Buffer.from([0,0,255,255]),Cn=Symbol("permessage-deflate"),yt=Symbol("total-length"),Jt=Symbol("callback"),St=Symbol("buffers"),Xt=Symbol("error"),Sn,Ea=class{constructor(t){if(this._options=t||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,!Sn){let e=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;Sn=new Tc(e)}}static get extensionName(){return"permessage-deflate"}offer(){let t={};return this._options.serverNoContextTakeover&&(t.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(t.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(t.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?t.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits==null&&(t.client_max_window_bits=!0),t}accept(t){return t=this.normalizeParams(t),this.params=this._isServer?this.acceptAsServer(t):this.acceptAsClient(t),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){let t=this._deflate[Jt];this._deflate.close(),this._deflate=null,t&&t(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(t){let e=this._options,s=t.find(n=>!(e.serverNoContextTakeover===!1&&n.server_no_context_takeover||n.server_max_window_bits&&(e.serverMaxWindowBits===!1||typeof e.serverMaxWindowBits=="number"&&e.serverMaxWindowBits>n.server_max_window_bits)||typeof e.clientMaxWindowBits=="number"&&!n.client_max_window_bits));if(!s)throw new Error("None of the extension offers can be accepted");return e.serverNoContextTakeover&&(s.server_no_context_takeover=!0),e.clientNoContextTakeover&&(s.client_no_context_takeover=!0),typeof e.serverMaxWindowBits=="number"&&(s.server_max_window_bits=e.serverMaxWindowBits),typeof e.clientMaxWindowBits=="number"?s.client_max_window_bits=e.clientMaxWindowBits:(s.client_max_window_bits===!0||e.clientMaxWindowBits===!1)&&delete s.client_max_window_bits,s}acceptAsClient(t){let e=t[0];if(this._options.clientNoContextTakeover===!1&&e.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(!e.client_max_window_bits)typeof this._options.clientMaxWindowBits=="number"&&(e.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits=="number"&&e.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"');return e}normalizeParams(t){return t.forEach(e=>{Object.keys(e).forEach(s=>{let n=e[s];if(n.length>1)throw new Error(`Parameter "${s}" must have only a single value`);if(n=n[0],s==="client_max_window_bits"){if(n!==!0){let a=+n;if(!Number.isInteger(a)||a<8||a>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=a}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else if(s==="server_max_window_bits"){let a=+n;if(!Number.isInteger(a)||a<8||a>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=a}else if(s==="client_no_context_takeover"||s==="server_no_context_takeover"){if(n!==!0)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else throw new Error(`Unknown parameter "${s}"`);e[s]=n})}),t}decompress(t,e,s){Sn.add(n=>{this._decompress(t,e,(a,i)=>{n(),s(a,i)})})}compress(t,e,s){Sn.add(n=>{this._compress(t,e,(a,i)=>{n(),s(a,i)})})}_decompress(t,e,s){let n=this._isServer?"client":"server";if(!this._inflate){let a=`${n}_max_window_bits`,i=typeof this.params[a]!="number"?As.Z_DEFAULT_WINDOWBITS:this.params[a];this._inflate=As.createInflateRaw({...this._options.zlibInflateOptions,windowBits:i}),this._inflate[Cn]=this,this._inflate[yt]=0,this._inflate[St]=[],this._inflate.on("error",Pc),this._inflate.on("data",Ni)}this._inflate[Jt]=s,this._inflate.write(t),e&&this._inflate.write(Ac),this._inflate.flush(()=>{let a=this._inflate[Xt];if(a){this._inflate.close(),this._inflate=null,s(a);return}let i=Fi.concat(this._inflate[St],this._inflate[yt]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[yt]=0,this._inflate[St]=[],e&&this.params[`${n}_no_context_takeover`]&&this._inflate.reset()),s(null,i)})}_compress(t,e,s){let n=this._isServer?"server":"client";if(!this._deflate){let a=`${n}_max_window_bits`,i=typeof this.params[a]!="number"?As.Z_DEFAULT_WINDOWBITS:this.params[a];this._deflate=As.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:i}),this._deflate[yt]=0,this._deflate[St]=[],this._deflate.on("data",Ec)}this._deflate[Jt]=s,this._deflate.write(t),this._deflate.flush(As.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let a=Fi.concat(this._deflate[St],this._deflate[yt]);e&&(a=new _c(a.buffer,a.byteOffset,a.length-4)),this._deflate[Jt]=null,this._deflate[yt]=0,this._deflate[St]=[],e&&this.params[`${n}_no_context_takeover`]&&this._deflate.reset(),s(null,a)})}};Bi.exports=Ea;function Ec(r){this[St].push(r),this[yt]+=r.length}function Ni(r){if(this[yt]+=r.length,this[Cn]._maxPayload<1||this[yt]<=this[Cn]._maxPayload){this[St].push(r);return}this[Xt]=new RangeError("Max payload size exceeded"),this[Xt].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[Xt][Oi]=1009,this.removeListener("data",Ni),this.reset()}function Pc(r){if(this[Cn]._inflate=null,this[Xt]){this[Jt](this[Xt]);return}r[Oi]=1007,this[Jt](r)}});var Zt=Ve((Ap,Tn)=>{"use strict";var{isUtf8:Ui}=require("buffer"),{hasBlob:Rc}=gt(),Dc=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function Ic(r){return r>=1e3&&r<=1014&&r!==1004&&r!==1005&&r!==1006||r>=3e3&&r<=4999}function Pa(r){let t=r.length,e=0;for(;e<t;)if((r[e]&128)===0)e++;else if((r[e]&224)===192){if(e+1===t||(r[e+1]&192)!==128||(r[e]&254)===192)return!1;e+=2}else if((r[e]&240)===224){if(e+2>=t||(r[e+1]&192)!==128||(r[e+2]&192)!==128||r[e]===224&&(r[e+1]&224)===128||r[e]===237&&(r[e+1]&224)===160)return!1;e+=3}else if((r[e]&248)===240){if(e+3>=t||(r[e+1]&192)!==128||(r[e+2]&192)!==128||(r[e+3]&192)!==128||r[e]===240&&(r[e+1]&240)===128||r[e]===244&&r[e+1]>143||r[e]>244)return!1;e+=4}else return!1;return!0}function Mc(r){return Rc&&typeof r=="object"&&typeof r.arrayBuffer=="function"&&typeof r.type=="string"&&typeof r.stream=="function"&&(r[Symbol.toStringTag]==="Blob"||r[Symbol.toStringTag]==="File")}Tn.exports={isBlob:Mc,isValidStatusCode:Ic,isValidUTF8:Pa,tokenChars:Dc};if(Ui)Tn.exports.isValidUTF8=function(r){return r.length<24?Pa(r):Ui(r)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let r=require("utf-8-validate");Tn.exports.isValidUTF8=function(t){return t.length<32?Pa(t):r(t)}}catch{}});var La=Ve((Ep,Gi)=>{"use strict";var{Writable:Lc}=require("stream"),$i=Qt(),{BINARY_TYPES:Fc,EMPTY_BUFFER:ji,kStatusCode:Oc,kWebSocket:Nc}=gt(),{concat:Ra,toArrayBuffer:Bc,unmask:Uc}=_s(),{isValidStatusCode:$c,isValidUTF8:Wi}=Zt(),_n=Buffer[Symbol.species],et=0,Hi=1,qi=2,zi=3,Da=4,Ia=5,An=6,Ma=class extends Lc{constructor(t={}){super(),this._allowSynchronousEvents=t.allowSynchronousEvents!==void 0?t.allowSynchronousEvents:!0,this._binaryType=t.binaryType||Fc[0],this._extensions=t.extensions||{},this._isServer=!!t.isServer,this._maxBufferedChunks=t.maxBufferedChunks|0,this._maxFragments=t.maxFragments|0,this._maxPayload=t.maxPayload|0,this._skipUTF8Validation=!!t.skipUTF8Validation,this[Nc]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=et}_write(t,e,s){if(this._opcode===8&&this._state==et)return s();if(this._maxBufferedChunks>0&&this._buffers.length>=this._maxBufferedChunks){s(this.createError(RangeError,"Too many buffered chunks",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS"));return}this._bufferedBytes+=t.length,this._buffers.push(t),this.startLoop(s)}consume(t){if(this._bufferedBytes-=t,t===this._buffers[0].length)return this._buffers.shift();if(t<this._buffers[0].length){let s=this._buffers[0];return this._buffers[0]=new _n(s.buffer,s.byteOffset+t,s.length-t),new _n(s.buffer,s.byteOffset,t)}let e=Buffer.allocUnsafe(t);do{let s=this._buffers[0],n=e.length-t;t>=s.length?e.set(this._buffers.shift(),n):(e.set(new Uint8Array(s.buffer,s.byteOffset,t),n),this._buffers[0]=new _n(s.buffer,s.byteOffset+t,s.length-t)),t-=s.length}while(t>0);return e}startLoop(t){this._loop=!0;do switch(this._state){case et:this.getInfo(t);break;case Hi:this.getPayloadLength16(t);break;case qi:this.getPayloadLength64(t);break;case zi:this.getMask();break;case Da:this.getData(t);break;case Ia:case An:this._loop=!1;return}while(this._loop);this._errored||t()}getInfo(t){if(this._bufferedBytes<2){this._loop=!1;return}let e=this.consume(2);if((e[0]&48)!==0){let n=this.createError(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");t(n);return}let s=(e[0]&64)===64;if(s&&!this._extensions[$i.extensionName]){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");t(n);return}if(this._fin=(e[0]&128)===128,this._opcode=e[0]&15,this._payloadLength=e[1]&127,this._opcode===0){if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");t(n);return}if(!this._fragmented){let n=this.createError(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");t(n);return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");t(n);return}this._compressed=s}else if(this._opcode>7&&this._opcode<11){if(!this._fin){let n=this.createError(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");t(n);return}if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");t(n);return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){let n=this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");t(n);return}}else{let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");t(n);return}if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(e[1]&128)===128,this._isServer){if(!this._masked){let n=this.createError(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK");t(n);return}}else if(this._masked){let n=this.createError(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");t(n);return}this._payloadLength===126?this._state=Hi:this._payloadLength===127?this._state=qi:this.haveLength(t)}getPayloadLength16(t){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength(t)}getPayloadLength64(t){if(this._bufferedBytes<8){this._loop=!1;return}let e=this.consume(8),s=e.readUInt32BE(0);if(s>Math.pow(2,21)-1){let n=this.createError(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH");t(n);return}this._payloadLength=s*Math.pow(2,32)+e.readUInt32BE(4),this.haveLength(t)}haveLength(t){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0)){let e=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");t(e);return}this._masked?this._state=zi:this._state=Da}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=Da}getData(t){let e=ji;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}e=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0&&Uc(e,this._mask)}if(this._opcode>7){this.controlMessage(e,t);return}if(this._compressed){this._state=Ia,this.decompress(e,t);return}if(e.length){if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let s=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");t(s);return}this._messageLength=this._totalPayloadLength,this._fragments.push(e)}this.dataMessage(t)}decompress(t,e){this._extensions[$i.extensionName].decompress(t,this._fin,(n,a)=>{if(n)return e(n);if(a.length){if(this._messageLength+=a.length,this._messageLength>this._maxPayload&&this._maxPayload>0){let i=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");e(i);return}if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let i=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");e(i);return}this._fragments.push(a)}this.dataMessage(e),this._state===et&&this.startLoop(e)})}dataMessage(t){if(!this._fin){this._state=et;return}let e=this._messageLength,s=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],this._opcode===2){let n;this._binaryType==="nodebuffer"?n=Ra(s,e):this._binaryType==="arraybuffer"?n=Bc(Ra(s,e)):this._binaryType==="blob"?n=new Blob(s):n=s,this._allowSynchronousEvents?(this.emit("message",n,!0),this._state=et):(this._state=An,setImmediate(()=>{this.emit("message",n,!0),this._state=et,this.startLoop(t)}))}else{let n=Ra(s,e);if(!this._skipUTF8Validation&&!Wi(n)){let a=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");t(a);return}this._state===Ia||this._allowSynchronousEvents?(this.emit("message",n,!1),this._state=et):(this._state=An,setImmediate(()=>{this.emit("message",n,!1),this._state=et,this.startLoop(t)}))}}controlMessage(t,e){if(this._opcode===8){if(t.length===0)this._loop=!1,this.emit("conclude",1005,ji),this.end();else{let s=t.readUInt16BE(0);if(!$c(s)){let a=this.createError(RangeError,`invalid status code ${s}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");e(a);return}let n=new _n(t.buffer,t.byteOffset+2,t.length-2);if(!this._skipUTF8Validation&&!Wi(n)){let a=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");e(a);return}this._loop=!1,this.emit("conclude",s,n),this.end()}this._state=et;return}this._allowSynchronousEvents?(this.emit(this._opcode===9?"ping":"pong",t),this._state=et):(this._state=An,setImmediate(()=>{this.emit(this._opcode===9?"ping":"pong",t),this._state=et,this.startLoop(e)}))}createError(t,e,s,n,a){this._loop=!1,this._errored=!0;let i=new t(s?`Invalid WebSocket frame: ${e}`:e);return Error.captureStackTrace(i,this.createError),i.code=a,i[Oc]=n,i}};Gi.exports=Ma});var Na=Ve((Rp,Ki)=>{"use strict";var{Duplex:Pp}=require("stream"),{randomFillSync:jc}=require("crypto"),{types:{isUint8Array:Wc}}=require("util"),Vi=Qt(),{EMPTY_BUFFER:Hc,kWebSocket:qc,NOOP:zc}=gt(),{isBlob:es,isValidStatusCode:Gc}=Zt(),{mask:Yi,toBuffer:Mt}=_s(),tt=Symbol("kByteLength"),Vc=Buffer.alloc(4),En=8*1024,Lt,ts=En,lt=0,Yc=1,Kc=2,Fa=class r{constructor(t,e,s){this._extensions=e||{},s&&(this._generateMask=s,this._maskBuffer=Buffer.alloc(4)),this._socket=t,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=lt,this.onerror=zc,this[qc]=void 0}static frame(t,e){let s,n=!1,a=2,i=!1;e.mask&&(s=e.maskBuffer||Vc,e.generateMask?e.generateMask(s):(ts===En&&(Lt===void 0&&(Lt=Buffer.alloc(En)),jc(Lt,0,En),ts=0),s[0]=Lt[ts++],s[1]=Lt[ts++],s[2]=Lt[ts++],s[3]=Lt[ts++]),i=(s[0]|s[1]|s[2]|s[3])===0,a=6);let o;typeof t=="string"?(!e.mask||i)&&e[tt]!==void 0?o=e[tt]:(t=Buffer.from(t),o=t.length):(o=t.length,n=e.mask&&e.readOnly&&!i);let c=o;o>=65536?(a+=8,c=127):o>125&&(a+=2,c=126);let l=Buffer.allocUnsafe(n?o+a:a);return l[0]=e.fin?e.opcode|128:e.opcode,e.rsv1&&(l[0]|=64),l[1]=c,c===126?l.writeUInt16BE(o,2):c===127&&(l[2]=l[3]=0,l.writeUIntBE(o,4,6)),e.mask?(l[1]|=128,l[a-4]=s[0],l[a-3]=s[1],l[a-2]=s[2],l[a-1]=s[3],i?[l,t]:n?(Yi(t,s,l,a,o),[l]):(Yi(t,s,t,0,o),[l,t])):[l,t]}close(t,e,s,n){let a;if(t===void 0)a=Hc;else{if(typeof t!="number"||!Gc(t))throw new TypeError("First argument must be a valid error code number");if(e===void 0||!e.length)a=Buffer.allocUnsafe(2),a.writeUInt16BE(t,0);else{let o=Buffer.byteLength(e);if(o>123)throw new RangeError("The message must not be greater than 123 bytes");if(a=Buffer.allocUnsafe(2+o),a.writeUInt16BE(t,0),typeof e=="string")a.write(e,2);else if(Wc(e))a.set(e,2);else throw new TypeError("Second argument must be a string or a Uint8Array")}}let i={[tt]:a.length,fin:!0,generateMask:this._generateMask,mask:s,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};this._state!==lt?this.enqueue([this.dispatch,a,!1,i,n]):this.sendFrame(r.frame(a,i),n)}ping(t,e,s){let n,a;if(typeof t=="string"?(n=Buffer.byteLength(t),a=!1):es(t)?(n=t.size,a=!1):(t=Mt(t),n=t.length,a=Mt.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let i={[tt]:n,fin:!0,generateMask:this._generateMask,mask:e,maskBuffer:this._maskBuffer,opcode:9,readOnly:a,rsv1:!1};es(t)?this._state!==lt?this.enqueue([this.getBlobData,t,!1,i,s]):this.getBlobData(t,!1,i,s):this._state!==lt?this.enqueue([this.dispatch,t,!1,i,s]):this.sendFrame(r.frame(t,i),s)}pong(t,e,s){let n,a;if(typeof t=="string"?(n=Buffer.byteLength(t),a=!1):es(t)?(n=t.size,a=!1):(t=Mt(t),n=t.length,a=Mt.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let i={[tt]:n,fin:!0,generateMask:this._generateMask,mask:e,maskBuffer:this._maskBuffer,opcode:10,readOnly:a,rsv1:!1};es(t)?this._state!==lt?this.enqueue([this.getBlobData,t,!1,i,s]):this.getBlobData(t,!1,i,s):this._state!==lt?this.enqueue([this.dispatch,t,!1,i,s]):this.sendFrame(r.frame(t,i),s)}send(t,e,s){let n=this._extensions[Vi.extensionName],a=e.binary?2:1,i=e.compress,o,c;typeof t=="string"?(o=Buffer.byteLength(t),c=!1):es(t)?(o=t.size,c=!1):(t=Mt(t),o=t.length,c=Mt.readOnly),this._firstFragment?(this._firstFragment=!1,i&&n&&n.params[n._isServer?"server_no_context_takeover":"client_no_context_takeover"]&&(i=o>=n._threshold),this._compress=i):(i=!1,a=0),e.fin&&(this._firstFragment=!0);let l={[tt]:o,fin:e.fin,generateMask:this._generateMask,mask:e.mask,maskBuffer:this._maskBuffer,opcode:a,readOnly:c,rsv1:i};es(t)?this._state!==lt?this.enqueue([this.getBlobData,t,this._compress,l,s]):this.getBlobData(t,this._compress,l,s):this._state!==lt?this.enqueue([this.dispatch,t,this._compress,l,s]):this.dispatch(t,this._compress,l,s)}getBlobData(t,e,s,n){this._bufferedBytes+=s[tt],this._state=Kc,t.arrayBuffer().then(a=>{if(this._socket.destroyed){let o=new Error("The socket was closed while the blob was being read");process.nextTick(Oa,this,o,n);return}this._bufferedBytes-=s[tt];let i=Mt(a);e?this.dispatch(i,e,s,n):(this._state=lt,this.sendFrame(r.frame(i,s),n),this.dequeue())}).catch(a=>{process.nextTick(Jc,this,a,n)})}dispatch(t,e,s,n){if(!e){this.sendFrame(r.frame(t,s),n);return}let a=this._extensions[Vi.extensionName];this._bufferedBytes+=s[tt],this._state=Yc,a.compress(t,s.fin,(i,o)=>{if(this._socket.destroyed){let c=new Error("The socket was closed while data was being compressed");Oa(this,c,n);return}this._bufferedBytes-=s[tt],this._state=lt,s.readOnly=!1,this.sendFrame(r.frame(o,s),n),this.dequeue()})}dequeue(){for(;this._state===lt&&this._queue.length;){let t=this._queue.shift();this._bufferedBytes-=t[3][tt],Reflect.apply(t[0],this,t.slice(1))}}enqueue(t){this._bufferedBytes+=t[3][tt],this._queue.push(t)}sendFrame(t,e){t.length===2?(this._socket.cork(),this._socket.write(t[0]),this._socket.write(t[1],e),this._socket.uncork()):this._socket.write(t[0],e)}};Ki.exports=Fa;function Oa(r,t,e){typeof e=="function"&&e(t);for(let s=0;s<r._queue.length;s++){let n=r._queue[s],a=n[n.length-1];typeof a=="function"&&a(t)}}function Jc(r,t,e){Oa(r,t,e),r.onerror(t)}});var ao=Ve((Dp,no)=>{"use strict";var{kForOnEventAttribute:Es,kListener:Ba}=gt(),Ji=Symbol("kCode"),Xi=Symbol("kData"),Qi=Symbol("kError"),Zi=Symbol("kMessage"),eo=Symbol("kReason"),ss=Symbol("kTarget"),to=Symbol("kType"),so=Symbol("kWasClean"),vt=class{constructor(t){this[ss]=null,this[to]=t}get target(){return this[ss]}get type(){return this[to]}};Object.defineProperty(vt.prototype,"target",{enumerable:!0});Object.defineProperty(vt.prototype,"type",{enumerable:!0});var Ft=class extends vt{constructor(t,e={}){super(t),this[Ji]=e.code===void 0?0:e.code,this[eo]=e.reason===void 0?"":e.reason,this[so]=e.wasClean===void 0?!1:e.wasClean}get code(){return this[Ji]}get reason(){return this[eo]}get wasClean(){return this[so]}};Object.defineProperty(Ft.prototype,"code",{enumerable:!0});Object.defineProperty(Ft.prototype,"reason",{enumerable:!0});Object.defineProperty(Ft.prototype,"wasClean",{enumerable:!0});var ns=class extends vt{constructor(t,e={}){super(t),this[Qi]=e.error===void 0?null:e.error,this[Zi]=e.message===void 0?"":e.message}get error(){return this[Qi]}get message(){return this[Zi]}};Object.defineProperty(ns.prototype,"error",{enumerable:!0});Object.defineProperty(ns.prototype,"message",{enumerable:!0});var Ps=class extends vt{constructor(t,e={}){super(t),this[Xi]=e.data===void 0?null:e.data}get data(){return this[Xi]}};Object.defineProperty(Ps.prototype,"data",{enumerable:!0});var Xc={addEventListener(r,t,e={}){for(let n of this.listeners(r))if(!e[Es]&&n[Ba]===t&&!n[Es])return;let s;if(r==="message")s=function(a,i){let o=new Ps("message",{data:i?a:a.toString()});o[ss]=this,Pn(t,this,o)};else if(r==="close")s=function(a,i){let o=new Ft("close",{code:a,reason:i.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});o[ss]=this,Pn(t,this,o)};else if(r==="error")s=function(a){let i=new ns("error",{error:a,message:a.message});i[ss]=this,Pn(t,this,i)};else if(r==="open")s=function(){let a=new vt("open");a[ss]=this,Pn(t,this,a)};else return;s[Es]=!!e[Es],s[Ba]=t,e.once?this.once(r,s):this.on(r,s)},removeEventListener(r,t){for(let e of this.listeners(r))if(e[Ba]===t&&!e[Es]){this.removeListener(r,e);break}}};no.exports={CloseEvent:Ft,ErrorEvent:ns,Event:vt,EventTarget:Xc,MessageEvent:Ps};function Pn(r,t,e){typeof r=="object"&&r.handleEvent?r.handleEvent.call(r,e):r.call(t,e)}});var Rn=Ve((Ip,ro)=>{"use strict";var{tokenChars:Rs}=Zt();function pt(r,t,e){r[t]===void 0?r[t]=[e]:r[t].push(e)}function Qc(r){let t=Object.create(null),e=Object.create(null),s=!1,n=!1,a=!1,i,o,c=-1,l=-1,h=-1,d=0;for(;d<r.length;d++)if(l=r.charCodeAt(d),i===void 0)if(h===-1&&Rs[l]===1)c===-1&&(c=d);else if(d!==0&&(l===32||l===9))h===-1&&c!==-1&&(h=d);else if(l===59||l===44){if(c===-1)throw new SyntaxError(`Unexpected character at index ${d}`);h===-1&&(h=d);let p=r.slice(c,h);l===44?(pt(t,p,e),e=Object.create(null)):i=p,c=h=-1}else throw new SyntaxError(`Unexpected character at index ${d}`);else if(o===void 0)if(h===-1&&Rs[l]===1)c===-1&&(c=d);else if(l===32||l===9)h===-1&&c!==-1&&(h=d);else if(l===59||l===44){if(c===-1)throw new SyntaxError(`Unexpected character at index ${d}`);h===-1&&(h=d),pt(e,r.slice(c,h),!0),l===44&&(pt(t,i,e),e=Object.create(null),i=void 0),c=h=-1}else if(l===61&&c!==-1&&h===-1)o=r.slice(c,d),c=h=-1;else throw new SyntaxError(`Unexpected character at index ${d}`);else if(n){if(Rs[l]!==1)throw new SyntaxError(`Unexpected character at index ${d}`);c===-1?c=d:s||(s=!0),n=!1}else if(a)if(Rs[l]===1)c===-1&&(c=d);else if(l===34&&c!==-1)a=!1,h=d;else if(l===92)n=!0;else throw new SyntaxError(`Unexpected character at index ${d}`);else if(l===34&&r.charCodeAt(d-1)===61)a=!0;else if(h===-1&&Rs[l]===1)c===-1&&(c=d);else if(c!==-1&&(l===32||l===9))h===-1&&(h=d);else if(l===59||l===44){if(c===-1)throw new SyntaxError(`Unexpected character at index ${d}`);h===-1&&(h=d);let p=r.slice(c,h);s&&(p=p.replace(/\\/g,""),s=!1),pt(e,o,p),l===44&&(pt(t,i,e),e=Object.create(null),i=void 0),o=void 0,c=h=-1}else throw new SyntaxError(`Unexpected character at index ${d}`);if(c===-1||a||l===32||l===9)throw new SyntaxError("Unexpected end of input");h===-1&&(h=d);let u=r.slice(c,h);return i===void 0?pt(t,u,e):(o===void 0?pt(e,u,!0):s?pt(e,o,u.replace(/\\/g,"")):pt(e,o,u),pt(t,i,e)),t}function Zc(r){return Object.keys(r).map(t=>{let e=r[t];return Array.isArray(e)||(e=[e]),e.map(s=>[t].concat(Object.keys(s).map(n=>{let a=s[n];return Array.isArray(a)||(a=[a]),a.map(i=>i===!0?n:`${n}=${i}`).join("; ")})).join("; ")).join(", ")}).join(", ")}ro.exports={format:Zc,parse:Qc}});var Ln=Ve((Fp,vo)=>{"use strict";var ed=require("events"),td=require("https"),sd=require("http"),lo=require("net"),nd=require("tls"),{randomBytes:ad,createHash:rd}=require("crypto"),{Duplex:Mp,Readable:Lp}=require("stream"),{URL:Ua}=require("url"),Ct=Qt(),id=La(),od=Na(),{isBlob:ld}=Zt(),{BINARY_TYPES:io,CLOSE_TIMEOUT:cd,EMPTY_BUFFER:Dn,GUID:dd,kForOnEventAttribute:$a,kListener:hd,kStatusCode:ud,kWebSocket:De,NOOP:co}=gt(),{EventTarget:{addEventListener:pd,removeEventListener:md}}=ao(),{format:fd,parse:gd}=Rn(),{toBuffer:yd}=_s(),ho=Symbol("kAborted"),ja=[8,13],wt=["CONNECTING","OPEN","CLOSING","CLOSED"],vd=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/,be=class r extends ed{constructor(t,e,s){super(),this._binaryType=io[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=Dn,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol="",this._readyState=r.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,t!==null?(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,e===void 0?e=[]:Array.isArray(e)||(typeof e=="object"&&e!==null?(s=e,e=[]):e=[e]),uo(this,t,e,s)):(this._autoPong=s.autoPong,this._closeTimeout=s.closeTimeout,this._isServer=!0)}get binaryType(){return this._binaryType}set binaryType(t){io.includes(t)&&(this._binaryType=t,this._receiver&&(this._receiver._binaryType=t))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(t,e,s){let n=new id({allowSynchronousEvents:s.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxBufferedChunks:s.maxBufferedChunks,maxFragments:s.maxFragments,maxPayload:s.maxPayload,skipUTF8Validation:s.skipUTF8Validation}),a=new od(t,this._extensions,s.generateMask);this._receiver=n,this._sender=a,this._socket=t,n[De]=this,a[De]=this,t[De]=this,n.on("conclude",kd),n.on("drain",xd),n.on("error",Sd),n.on("message",Cd),n.on("ping",Td),n.on("pong",_d),a.onerror=Ad,t.setTimeout&&t.setTimeout(0),t.setNoDelay&&t.setNoDelay(),e.length>0&&t.unshift(e),t.on("close",fo),t.on("data",Mn),t.on("end",go),t.on("error",yo),this._readyState=r.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=r.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}this._extensions[Ct.extensionName]&&this._extensions[Ct.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=r.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(t,e){if(this.readyState!==r.CLOSED){if(this.readyState===r.CONNECTING){Qe(this,this._req,"WebSocket was closed before the connection was established");return}if(this.readyState===r.CLOSING){this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end();return}this._readyState=r.CLOSING,this._sender.close(t,e,!this._isServer,s=>{s||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())}),mo(this)}}pause(){this.readyState===r.CONNECTING||this.readyState===r.CLOSED||(this._paused=!0,this._socket.pause())}ping(t,e,s){if(this.readyState===r.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof t=="function"?(s=t,t=e=void 0):typeof e=="function"&&(s=e,e=void 0),typeof t=="number"&&(t=t.toString()),this.readyState!==r.OPEN){Wa(this,t,s);return}e===void 0&&(e=!this._isServer),this._sender.ping(t||Dn,e,s)}pong(t,e,s){if(this.readyState===r.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof t=="function"?(s=t,t=e=void 0):typeof e=="function"&&(s=e,e=void 0),typeof t=="number"&&(t=t.toString()),this.readyState!==r.OPEN){Wa(this,t,s);return}e===void 0&&(e=!this._isServer),this._sender.pong(t||Dn,e,s)}resume(){this.readyState===r.CONNECTING||this.readyState===r.CLOSED||(this._paused=!1,this._receiver._writableState.needDrain||this._socket.resume())}send(t,e,s){if(this.readyState===r.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"&&(s=e,e={}),typeof t=="number"&&(t=t.toString()),this.readyState!==r.OPEN){Wa(this,t,s);return}let n={binary:typeof t!="string",mask:!this._isServer,compress:!0,fin:!0,...e};this._extensions[Ct.extensionName]||(n.compress=!1),this._sender.send(t||Dn,n,s)}terminate(){if(this.readyState!==r.CLOSED){if(this.readyState===r.CONNECTING){Qe(this,this._req,"WebSocket was closed before the connection was established");return}this._socket&&(this._readyState=r.CLOSING,this._socket.destroy())}}};Object.defineProperty(be,"CONNECTING",{enumerable:!0,value:wt.indexOf("CONNECTING")});Object.defineProperty(be.prototype,"CONNECTING",{enumerable:!0,value:wt.indexOf("CONNECTING")});Object.defineProperty(be,"OPEN",{enumerable:!0,value:wt.indexOf("OPEN")});Object.defineProperty(be.prototype,"OPEN",{enumerable:!0,value:wt.indexOf("OPEN")});Object.defineProperty(be,"CLOSING",{enumerable:!0,value:wt.indexOf("CLOSING")});Object.defineProperty(be.prototype,"CLOSING",{enumerable:!0,value:wt.indexOf("CLOSING")});Object.defineProperty(be,"CLOSED",{enumerable:!0,value:wt.indexOf("CLOSED")});Object.defineProperty(be.prototype,"CLOSED",{enumerable:!0,value:wt.indexOf("CLOSED")});["binaryType","bufferedAmount","extensions","isPaused","protocol","readyState","url"].forEach(r=>{Object.defineProperty(be.prototype,r,{enumerable:!0})});["open","error","close","message"].forEach(r=>{Object.defineProperty(be.prototype,`on${r}`,{enumerable:!0,get(){for(let t of this.listeners(r))if(t[$a])return t[hd];return null},set(t){for(let e of this.listeners(r))if(e[$a]){this.removeListener(r,e);break}typeof t=="function"&&this.addEventListener(r,t,{[$a]:!0})}})});be.prototype.addEventListener=pd;be.prototype.removeEventListener=md;vo.exports=be;function uo(r,t,e,s){let n={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:cd,protocolVersion:ja[1],maxBufferedChunks:1048576,maxFragments:131072,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...s,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:"GET",host:void 0,path:void 0,port:void 0};if(r._autoPong=n.autoPong,r._closeTimeout=n.closeTimeout,!ja.includes(n.protocolVersion))throw new RangeError(`Unsupported protocol version: ${n.protocolVersion} (supported versions: ${ja.join(", ")})`);let a;if(t instanceof Ua)a=t;else try{a=new Ua(t)}catch{throw new SyntaxError(`Invalid URL: ${t}`)}a.protocol==="http:"?a.protocol="ws:":a.protocol==="https:"&&(a.protocol="wss:"),r._url=a.href;let i=a.protocol==="wss:",o=a.protocol==="ws+unix:",c;if(a.protocol!=="ws:"&&!i&&!o?c=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`:o&&!a.pathname?c="The URL's pathname is empty":a.hash&&(c="The URL contains a fragment identifier"),c){let f=new SyntaxError(c);if(r._redirects===0)throw f;In(r,f);return}let l=i?443:80,h=ad(16).toString("base64"),d=i?td.request:sd.request,u=new Set,p;if(n.createConnection=n.createConnection||(i?bd:wd),n.defaultPort=n.defaultPort||l,n.port=a.port||l,n.host=a.hostname.startsWith("[")?a.hostname.slice(1,-1):a.hostname,n.headers={...n.headers,"Sec-WebSocket-Version":n.protocolVersion,"Sec-WebSocket-Key":h,Connection:"Upgrade",Upgrade:"websocket"},n.path=a.pathname+a.search,n.timeout=n.handshakeTimeout,n.perMessageDeflate&&(p=new Ct({...n.perMessageDeflate,isServer:!1,maxPayload:n.maxPayload}),n.headers["Sec-WebSocket-Extensions"]=fd({[Ct.extensionName]:p.offer()})),e.length){for(let f of e){if(typeof f!="string"||!vd.test(f)||u.has(f))throw new SyntaxError("An invalid or duplicated subprotocol was specified");u.add(f)}n.headers["Sec-WebSocket-Protocol"]=e.join(",")}if(n.origin&&(n.protocolVersion<13?n.headers["Sec-WebSocket-Origin"]=n.origin:n.headers.Origin=n.origin),(a.username||a.password)&&(n.auth=`${a.username}:${a.password}`),o){let f=n.path.split(":");n.socketPath=f[0],n.path=f[1]}let m;if(n.followRedirects){if(r._redirects===0){r._originalIpc=o,r._originalSecure=i,r._originalHostOrSocketPath=o?n.socketPath:a.host;let f=s&&s.headers;if(s={...s,headers:{}},f)for(let[g,y]of Object.entries(f))s.headers[g.toLowerCase()]=y}else if(r.listenerCount("redirect")===0){let f=o?r._originalIpc?n.socketPath===r._originalHostOrSocketPath:!1:r._originalIpc?!1:a.host===r._originalHostOrSocketPath;(!f||r._originalSecure&&!i)&&(delete n.headers.authorization,delete n.headers.cookie,f||delete n.headers.host,n.auth=void 0)}n.auth&&!s.headers.authorization&&(s.headers.authorization="Basic "+Buffer.from(n.auth).toString("base64")),m=r._req=d(n),r._redirects&&r.emit("redirect",r.url,m)}else m=r._req=d(n);n.timeout&&m.on("timeout",()=>{Qe(r,m,"Opening handshake has timed out")}),m.on("error",f=>{m===null||m[ho]||(m=r._req=null,In(r,f))}),m.on("response",f=>{let g=f.headers.location,y=f.statusCode;if(g&&n.followRedirects&&y>=300&&y<400){if(++r._redirects>n.maxRedirects){Qe(r,m,"Maximum redirects exceeded");return}m.abort();let v;try{v=new Ua(g,t)}catch{let w=new SyntaxError(`Invalid URL: ${g}`);In(r,w);return}uo(r,v,e,s)}else r.emit("unexpected-response",m,f)||Qe(r,m,`Unexpected server response: ${f.statusCode}`)}),m.on("upgrade",(f,g,y)=>{if(r.emit("upgrade",f),r.readyState!==be.CONNECTING)return;m=r._req=null;let v=f.headers.upgrade;if(v===void 0||v.toLowerCase()!=="websocket"){Qe(r,g,"Invalid Upgrade header");return}let k=rd("sha1").update(h+dd).digest("base64");if(f.headers["sec-websocket-accept"]!==k){Qe(r,g,"Invalid Sec-WebSocket-Accept header");return}let w=f.headers["sec-websocket-protocol"],S;if(w!==void 0?u.size?u.has(w)||(S="Server sent an invalid subprotocol"):S="Server sent a subprotocol but none was requested":u.size&&(S="Server sent no subprotocol"),S){Qe(r,g,S);return}w&&(r._protocol=w);let T=f.headers["sec-websocket-extensions"];if(T!==void 0){if(!p){Qe(r,g,"Server sent a Sec-WebSocket-Extensions header but no extension was requested");return}let _;try{_=gd(T)}catch{Qe(r,g,"Invalid Sec-WebSocket-Extensions header");return}let D=Object.keys(_);if(D.length!==1||D[0]!==Ct.extensionName){Qe(r,g,"Server indicated an extension that was not requested");return}try{p.accept(_[Ct.extensionName])}catch{Qe(r,g,"Invalid Sec-WebSocket-Extensions header");return}r._extensions[Ct.extensionName]=p}r.setSocket(g,y,{allowSynchronousEvents:n.allowSynchronousEvents,generateMask:n.generateMask,maxBufferedChunks:n.maxBufferedChunks,maxFragments:n.maxFragments,maxPayload:n.maxPayload,skipUTF8Validation:n.skipUTF8Validation})}),n.finishRequest?n.finishRequest(m,r):m.end()}function In(r,t){r._readyState=be.CLOSING,r._errorEmitted=!0,r.emit("error",t),r.emitClose()}function wd(r){return r.path=r.socketPath,lo.connect(r)}function bd(r){return r.path=void 0,!r.servername&&r.servername!==""&&(r.servername=lo.isIP(r.host)?"":r.host),nd.connect(r)}function Qe(r,t,e){r._readyState=be.CLOSING;let s=new Error(e);Error.captureStackTrace(s,Qe),t.setHeader?(t[ho]=!0,t.abort(),t.socket&&!t.socket.destroyed&&t.socket.destroy(),process.nextTick(In,r,s)):(t.destroy(s),t.once("error",r.emit.bind(r,"error")),t.once("close",r.emitClose.bind(r)))}function Wa(r,t,e){if(t){let s=ld(t)?t.size:yd(t).length;r._socket?r._sender._bufferedBytes+=s:r._bufferedAmount+=s}if(e){let s=new Error(`WebSocket is not open: readyState ${r.readyState} (${wt[r.readyState]})`);process.nextTick(e,s)}}function kd(r,t){let e=this[De];e._closeFrameReceived=!0,e._closeMessage=t,e._closeCode=r,e._socket[De]!==void 0&&(e._socket.removeListener("data",Mn),process.nextTick(po,e._socket),r===1005?e.close():e.close(r,t))}function xd(){let r=this[De];r.isPaused||r._socket.resume()}function Sd(r){let t=this[De];t._socket[De]!==void 0&&(t._socket.removeListener("data",Mn),process.nextTick(po,t._socket),t.close(r[ud])),t._errorEmitted||(t._errorEmitted=!0,t.emit("error",r))}function oo(){this[De].emitClose()}function Cd(r,t){this[De].emit("message",r,t)}function Td(r){let t=this[De];t._autoPong&&t.pong(r,!this._isServer,co),t.emit("ping",r)}function _d(r){this[De].emit("pong",r)}function po(r){r.resume()}function Ad(r){let t=this[De];t.readyState!==be.CLOSED&&(t.readyState===be.OPEN&&(t._readyState=be.CLOSING,mo(t)),this._socket.end(),t._errorEmitted||(t._errorEmitted=!0,t.emit("error",r)))}function mo(r){r._closeTimer=setTimeout(r._socket.destroy.bind(r._socket),r._closeTimeout)}function fo(){let r=this[De];if(this.removeListener("close",fo),this.removeListener("data",Mn),this.removeListener("end",go),r._readyState=be.CLOSING,!this._readableState.endEmitted&&!r._closeFrameReceived&&!r._receiver._writableState.errorEmitted&&this._readableState.length!==0){let t=this.read(this._readableState.length);r._receiver.write(t)}r._receiver.end(),this[De]=void 0,clearTimeout(r._closeTimer),r._receiver._writableState.finished||r._receiver._writableState.errorEmitted?r.emitClose():(r._receiver.on("error",oo),r._receiver.on("finish",oo))}function Mn(r){this[De]._receiver.write(r)||this.pause()}function go(){let r=this[De];r._readyState=be.CLOSING,r._receiver.end(),this.end()}function yo(){let r=this[De];this.removeListener("error",yo),this.on("error",co),r&&(r._readyState=be.CLOSING,this.destroy())}});var xo=Ve((Np,ko)=>{"use strict";var Op=Ln(),{Duplex:Ed}=require("stream");function wo(r){r.emit("close")}function Pd(){!this.destroyed&&this._writableState.finished&&this.destroy()}function bo(r){this.removeListener("error",bo),this.destroy(),this.listenerCount("error")===0&&this.emit("error",r)}function Rd(r,t){let e=!0,s=new Ed({...t,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return r.on("message",function(a,i){let o=!i&&s._readableState.objectMode?a.toString():a;s.push(o)||r.pause()}),r.once("error",function(a){s.destroyed||(e=!1,s.destroy(a))}),r.once("close",function(){s.destroyed||s.push(null)}),s._destroy=function(n,a){if(r.readyState===r.CLOSED){a(n),process.nextTick(wo,s);return}let i=!1;r.once("error",function(c){i=!0,a(c)}),r.once("close",function(){i||a(n),process.nextTick(wo,s)}),e&&r.terminate()},s._final=function(n){if(r.readyState===r.CONNECTING){r.once("open",function(){s._final(n)});return}r._socket!==null&&(r._socket._writableState.finished?(n(),s._readableState.endEmitted&&s.destroy()):(r._socket.once("finish",function(){n()}),r.close()))},s._read=function(){r.isPaused&&r.resume()},s._write=function(n,a,i){if(r.readyState===r.CONNECTING){r.once("open",function(){s._write(n,a,i)});return}r.send(n,i)},s.on("end",Pd),s.on("error",bo),s}ko.exports=Rd});var Ha=Ve((Bp,So)=>{"use strict";var{tokenChars:Dd}=Zt();function Id(r){let t=new Set,e=-1,s=-1,n=0;for(n;n<r.length;n++){let i=r.charCodeAt(n);if(s===-1&&Dd[i]===1)e===-1&&(e=n);else if(n!==0&&(i===32||i===9))s===-1&&e!==-1&&(s=n);else if(i===44){if(e===-1)throw new SyntaxError(`Unexpected character at index ${n}`);s===-1&&(s=n);let o=r.slice(e,s);if(t.has(o))throw new SyntaxError(`The "${o}" subprotocol is duplicated`);t.add(o),e=s=-1}else throw new SyntaxError(`Unexpected character at index ${n}`)}if(e===-1||s!==-1)throw new SyntaxError("Unexpected end of input");let a=r.slice(e,n);if(t.has(a))throw new SyntaxError(`The "${a}" subprotocol is duplicated`);return t.add(a),t}So.exports={parse:Id}});var Ro=Ve(($p,Po)=>{"use strict";var Md=require("events"),Fn=require("http"),{Duplex:Up}=require("stream"),{createHash:Ld}=require("crypto"),Co=Rn(),Ot=Qt(),Fd=Ha(),Od=Ln(),{CLOSE_TIMEOUT:Nd,GUID:Bd,kWebSocket:Ud}=gt(),$d=/^[+/0-9A-Za-z]{22}==$/,To=0,_o=1,Eo=2,qa=class extends Md{constructor(t,e){if(super(),t={allowSynchronousEvents:!0,autoPong:!0,maxBufferedChunks:1024*1024,maxFragments:128*1024,maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:Nd,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:Od,...t},t.port==null&&!t.server&&!t.noServer||t.port!=null&&(t.server||t.noServer)||t.server&&t.noServer)throw new TypeError('One and only one of the "port", "server", or "noServer" options must be specified');if(t.port!=null?(this._server=Fn.createServer((s,n)=>{let a=Fn.STATUS_CODES[426];n.writeHead(426,{"Content-Length":a.length,"Content-Type":"text/plain"}),n.end(a)}),this._server.listen(t.port,t.host,t.backlog,e)):t.server&&(this._server=t.server),this._server){let s=this.emit.bind(this,"connection");this._removeListeners=jd(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(n,a,i)=>{this.handleUpgrade(n,a,i,s)}})}t.perMessageDeflate===!0&&(t.perMessageDeflate={}),t.clientTracking&&(this.clients=new Set,this._shouldEmitClose=!1),this.options=t,this._state=To}address(){if(this.options.noServer)throw new Error('The server is operating in "noServer" mode');return this._server?this._server.address():null}close(t){if(this._state===Eo){t&&this.once("close",()=>{t(new Error("The server is not running"))}),process.nextTick(Ds,this);return}if(t&&this.once("close",t),this._state!==_o)if(this._state=_o,this.options.noServer||this.options.server)this._server&&(this._removeListeners(),this._removeListeners=this._server=null),this.clients?this.clients.size?this._shouldEmitClose=!0:process.nextTick(Ds,this):process.nextTick(Ds,this);else{let e=this._server;this._removeListeners(),this._removeListeners=this._server=null,e.close(()=>{Ds(this)})}}shouldHandle(t){if(this.options.path){let e=t.url.indexOf("?");if((e!==-1?t.url.slice(0,e):t.url)!==this.options.path)return!1}return!0}handleUpgrade(t,e,s,n){e.on("error",Ao);let a=t.headers["sec-websocket-key"],i=t.headers.upgrade,o=+t.headers["sec-websocket-version"];if(t.method!=="GET"){Nt(this,t,e,405,"Invalid HTTP method");return}if(i===void 0||i.toLowerCase()!=="websocket"){Nt(this,t,e,400,"Invalid Upgrade header");return}if(a===void 0||!$d.test(a)){Nt(this,t,e,400,"Missing or invalid Sec-WebSocket-Key header");return}if(o!==13&&o!==8){Nt(this,t,e,400,"Missing or invalid Sec-WebSocket-Version header",{"Sec-WebSocket-Version":"13, 8"});return}if(!this.shouldHandle(t)){Is(e,400);return}let c=t.headers["sec-websocket-protocol"],l=new Set;if(c!==void 0)try{l=Fd.parse(c)}catch{Nt(this,t,e,400,"Invalid Sec-WebSocket-Protocol header");return}let h=t.headers["sec-websocket-extensions"],d={};if(this.options.perMessageDeflate&&h!==void 0){let u=new Ot({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let p=Co.parse(h);p[Ot.extensionName]&&(u.accept(p[Ot.extensionName]),d[Ot.extensionName]=u)}catch{Nt(this,t,e,400,"Invalid or unacceptable Sec-WebSocket-Extensions header");return}}if(this.options.verifyClient){let u={origin:t.headers[`${o===8?"sec-websocket-origin":"origin"}`],secure:!!(t.socket.authorized||t.socket.encrypted),req:t};if(this.options.verifyClient.length===2){this.options.verifyClient(u,(p,m,f,g)=>{if(!p)return Is(e,m||401,f,g);this.completeUpgrade(d,a,l,t,e,s,n)});return}if(!this.options.verifyClient(u))return Is(e,401)}this.completeUpgrade(d,a,l,t,e,s,n)}completeUpgrade(t,e,s,n,a,i,o){if(!a.readable||!a.writable)return a.destroy();if(a[Ud])throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");if(this._state>To)return Is(a,503);let l=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${Ld("sha1").update(e+Bd).digest("base64")}`],h=new this.options.WebSocket(null,void 0,this.options);if(s.size){let d=this.options.handleProtocols?this.options.handleProtocols(s,n):s.values().next().value;d&&(l.push(`Sec-WebSocket-Protocol: ${d}`),h._protocol=d)}if(t[Ot.extensionName]){let d=t[Ot.extensionName].params,u=Co.format({[Ot.extensionName]:[d]});l.push(`Sec-WebSocket-Extensions: ${u}`),h._extensions=t}this.emit("headers",l,n),a.write(l.concat(`\r
|
|
1
|
+
"use strict";var Oc=Object.create;var wn=Object.defineProperty;var Nc=Object.getOwnPropertyDescriptor;var Bc=Object.getOwnPropertyNames;var Uc=Object.getPrototypeOf,$c=Object.prototype.hasOwnProperty;var tt=(a,e)=>()=>(e||a((e={exports:{}}).exports,e),e.exports),jc=(a,e)=>{for(var t in e)wn(a,t,{get:e[t],enumerable:!0})},Jr=(a,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Bc(e))!$c.call(a,n)&&n!==t&&wn(a,n,{get:()=>e[n],enumerable:!(s=Nc(e,n))||s.enumerable});return a};var st=(a,e,t)=>(t=a!=null?Oc(Uc(a)):{},Jr(e||!a||!a.__esModule?wn(t,"default",{value:a,enumerable:!0}):t,a)),Hc=a=>Jr(wn({},"__esModule",{value:!0}),a);var Rt=tt((ig,Io)=>{"use strict";var Do=["nodebuffer","arraybuffer","fragments"],Ro=typeof Blob<"u";Ro&&Do.push("blob");Io.exports={BINARY_TYPES:Do,CLOSE_TIMEOUT:3e4,EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",hasBlob:Ro,kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}}});var Zs=tt((og,ia)=>{"use strict";var{EMPTY_BUFFER:tu}=Rt(),fr=Buffer[Symbol.species];function su(a,e){if(a.length===0)return tu;if(a.length===1)return a[0];let t=Buffer.allocUnsafe(e),s=0;for(let n=0;n<a.length;n++){let r=a[n];t.set(r,s),s+=r.length}return s<e?new fr(t.buffer,t.byteOffset,s):t}function Mo(a,e,t,s,n){for(let r=0;r<n;r++)t[s+r]=a[r]^e[r&3]}function Fo(a,e){for(let t=0;t<a.length;t++)a[t]^=e[t&3]}function nu(a){return a.length===a.buffer.byteLength?a.buffer:a.buffer.slice(a.byteOffset,a.byteOffset+a.length)}function gr(a){if(gr.readOnly=!0,Buffer.isBuffer(a))return a;let e;return a instanceof ArrayBuffer?e=new fr(a):ArrayBuffer.isView(a)?e=new fr(a.buffer,a.byteOffset,a.byteLength):(e=Buffer.from(a),gr.readOnly=!1),e}ia.exports={concat:su,mask:Mo,toArrayBuffer:nu,toBuffer:gr,unmask:Fo};if(!process.env.WS_NO_BUFFER_UTIL)try{let a=require("bufferutil");ia.exports.mask=function(e,t,s,n,r){r<48?Mo(e,t,s,n,r):a.mask(e,t,s,n,r)},ia.exports.unmask=function(e,t){e.length<32?Fo(e,t):a.unmask(e,t)}}catch{}});var No=tt((lg,Oo)=>{"use strict";var Lo=Symbol("kDone"),yr=Symbol("kRun"),vr=class{constructor(e){this[Lo]=()=>{this.pending--,this[yr]()},this.concurrency=e||1/0,this.jobs=[],this.pending=0}add(e){this.jobs.push(e),this[yr]()}[yr](){if(this.pending!==this.concurrency&&this.jobs.length){let e=this.jobs.shift();this.pending++,e(this[Lo])}}};Oo.exports=vr});var ks=tt((cg,jo)=>{"use strict";var en=require("zlib"),Bo=Zs(),au=No(),{kStatusCode:Uo}=Rt(),ru=Buffer[Symbol.species],iu=Buffer.from([0,0,255,255]),la=Symbol("permessage-deflate"),It=Symbol("total-length"),ws=Symbol("callback"),$t=Symbol("buffers"),bs=Symbol("error"),oa,wr=class{constructor(e){if(this._options=e||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,!oa){let t=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;oa=new au(t)}}static get extensionName(){return"permessage-deflate"}offer(){let e={};return this._options.serverNoContextTakeover&&(e.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(e.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(e.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?e.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits==null&&(e.client_max_window_bits=!0),e}accept(e){return e=this.normalizeParams(e),this.params=this._isServer?this.acceptAsServer(e):this.acceptAsClient(e),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){let e=this._deflate[ws];this._deflate.close(),this._deflate=null,e&&e(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(e){let t=this._options,s=e.find(n=>!(t.serverNoContextTakeover===!1&&n.server_no_context_takeover||n.server_max_window_bits&&(t.serverMaxWindowBits===!1||typeof t.serverMaxWindowBits=="number"&&t.serverMaxWindowBits>n.server_max_window_bits)||typeof t.clientMaxWindowBits=="number"&&!n.client_max_window_bits));if(!s)throw new Error("None of the extension offers can be accepted");return t.serverNoContextTakeover&&(s.server_no_context_takeover=!0),t.clientNoContextTakeover&&(s.client_no_context_takeover=!0),typeof t.serverMaxWindowBits=="number"&&(s.server_max_window_bits=t.serverMaxWindowBits),typeof t.clientMaxWindowBits=="number"?s.client_max_window_bits=t.clientMaxWindowBits:(s.client_max_window_bits===!0||t.clientMaxWindowBits===!1)&&delete s.client_max_window_bits,s}acceptAsClient(e){let t=e[0];if(this._options.clientNoContextTakeover===!1&&t.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(!t.client_max_window_bits)typeof this._options.clientMaxWindowBits=="number"&&(t.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits=="number"&&t.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"');return t}normalizeParams(e){return e.forEach(t=>{Object.keys(t).forEach(s=>{let n=t[s];if(n.length>1)throw new Error(`Parameter "${s}" must have only a single value`);if(n=n[0],s==="client_max_window_bits"){if(n!==!0){let r=+n;if(!Number.isInteger(r)||r<8||r>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=r}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else if(s==="server_max_window_bits"){let r=+n;if(!Number.isInteger(r)||r<8||r>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=r}else if(s==="client_no_context_takeover"||s==="server_no_context_takeover"){if(n!==!0)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else throw new Error(`Unknown parameter "${s}"`);t[s]=n})}),e}decompress(e,t,s){oa.add(n=>{this._decompress(e,t,(r,i)=>{n(),s(r,i)})})}compress(e,t,s){oa.add(n=>{this._compress(e,t,(r,i)=>{n(),s(r,i)})})}_decompress(e,t,s){let n=this._isServer?"client":"server";if(!this._inflate){let r=`${n}_max_window_bits`,i=typeof this.params[r]!="number"?en.Z_DEFAULT_WINDOWBITS:this.params[r];this._inflate=en.createInflateRaw({...this._options.zlibInflateOptions,windowBits:i}),this._inflate[la]=this,this._inflate[It]=0,this._inflate[$t]=[],this._inflate.on("error",lu),this._inflate.on("data",$o)}this._inflate[ws]=s,this._inflate.write(e),t&&this._inflate.write(iu),this._inflate.flush(()=>{let r=this._inflate[bs];if(r){this._inflate.close(),this._inflate=null,s(r);return}let i=Bo.concat(this._inflate[$t],this._inflate[It]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[It]=0,this._inflate[$t]=[],t&&this.params[`${n}_no_context_takeover`]&&this._inflate.reset()),s(null,i)})}_compress(e,t,s){let n=this._isServer?"server":"client";if(!this._deflate){let r=`${n}_max_window_bits`,i=typeof this.params[r]!="number"?en.Z_DEFAULT_WINDOWBITS:this.params[r];this._deflate=en.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:i}),this._deflate[It]=0,this._deflate[$t]=[],this._deflate.on("data",ou)}this._deflate[ws]=s,this._deflate.write(e),this._deflate.flush(en.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let r=Bo.concat(this._deflate[$t],this._deflate[It]);t&&(r=new ru(r.buffer,r.byteOffset,r.length-4)),this._deflate[ws]=null,this._deflate[It]=0,this._deflate[$t]=[],t&&this.params[`${n}_no_context_takeover`]&&this._deflate.reset(),s(null,r)})}};jo.exports=wr;function ou(a){this[$t].push(a),this[It]+=a.length}function $o(a){if(this[It]+=a.length,this[la]._maxPayload<1||this[It]<=this[la]._maxPayload){this[$t].push(a);return}this[bs]=new RangeError("Max payload size exceeded"),this[bs].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[bs][Uo]=1009,this.removeListener("data",$o),this.reset()}function lu(a){if(this[la]._inflate=null,this[bs]){this[ws](this[bs]);return}a[Uo]=1007,this[ws](a)}});var xs=tt((dg,ca)=>{"use strict";var{isUtf8:Ho}=require("buffer"),{hasBlob:cu}=Rt(),du=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function uu(a){return a>=1e3&&a<=1014&&a!==1004&&a!==1005&&a!==1006||a>=3e3&&a<=4999}function br(a){let e=a.length,t=0;for(;t<e;)if((a[t]&128)===0)t++;else if((a[t]&224)===192){if(t+1===e||(a[t+1]&192)!==128||(a[t]&254)===192)return!1;t+=2}else if((a[t]&240)===224){if(t+2>=e||(a[t+1]&192)!==128||(a[t+2]&192)!==128||a[t]===224&&(a[t+1]&224)===128||a[t]===237&&(a[t+1]&224)===160)return!1;t+=3}else if((a[t]&248)===240){if(t+3>=e||(a[t+1]&192)!==128||(a[t+2]&192)!==128||(a[t+3]&192)!==128||a[t]===240&&(a[t+1]&240)===128||a[t]===244&&a[t+1]>143||a[t]>244)return!1;t+=4}else return!1;return!0}function hu(a){return cu&&typeof a=="object"&&typeof a.arrayBuffer=="function"&&typeof a.type=="string"&&typeof a.stream=="function"&&(a[Symbol.toStringTag]==="Blob"||a[Symbol.toStringTag]==="File")}ca.exports={isBlob:hu,isValidStatusCode:uu,isValidUTF8:br,tokenChars:du};if(Ho)ca.exports.isValidUTF8=function(a){return a.length<24?br(a):Ho(a)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let a=require("utf-8-validate");ca.exports.isValidUTF8=function(e){return e.length<32?br(e):a(e)}}catch{}});var Tr=tt((ug,Ko)=>{"use strict";var{Writable:pu}=require("stream"),Wo=ks(),{BINARY_TYPES:mu,EMPTY_BUFFER:qo,kStatusCode:fu,kWebSocket:gu}=Rt(),{concat:kr,toArrayBuffer:yu,unmask:vu}=Zs(),{isValidStatusCode:wu,isValidUTF8:zo}=xs(),da=Buffer[Symbol.species],ht=0,Go=1,Vo=2,Yo=3,xr=4,Sr=5,ua=6,Cr=class extends pu{constructor(e={}){super(),this._allowSynchronousEvents=e.allowSynchronousEvents!==void 0?e.allowSynchronousEvents:!0,this._binaryType=e.binaryType||mu[0],this._extensions=e.extensions||{},this._isServer=!!e.isServer,this._maxBufferedChunks=e.maxBufferedChunks|0,this._maxFragments=e.maxFragments|0,this._maxPayload=e.maxPayload|0,this._skipUTF8Validation=!!e.skipUTF8Validation,this[gu]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=ht}_write(e,t,s){if(this._opcode===8&&this._state==ht)return s();if(this._maxBufferedChunks>0&&this._buffers.length>=this._maxBufferedChunks){s(this.createError(RangeError,"Too many buffered chunks",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS"));return}this._bufferedBytes+=e.length,this._buffers.push(e),this.startLoop(s)}consume(e){if(this._bufferedBytes-=e,e===this._buffers[0].length)return this._buffers.shift();if(e<this._buffers[0].length){let s=this._buffers[0];return this._buffers[0]=new da(s.buffer,s.byteOffset+e,s.length-e),new da(s.buffer,s.byteOffset,e)}let t=Buffer.allocUnsafe(e);do{let s=this._buffers[0],n=t.length-e;e>=s.length?t.set(this._buffers.shift(),n):(t.set(new Uint8Array(s.buffer,s.byteOffset,e),n),this._buffers[0]=new da(s.buffer,s.byteOffset+e,s.length-e)),e-=s.length}while(e>0);return t}startLoop(e){this._loop=!0;do switch(this._state){case ht:this.getInfo(e);break;case Go:this.getPayloadLength16(e);break;case Vo:this.getPayloadLength64(e);break;case Yo:this.getMask();break;case xr:this.getData(e);break;case Sr:case ua:this._loop=!1;return}while(this._loop);this._errored||e()}getInfo(e){if(this._bufferedBytes<2){this._loop=!1;return}let t=this.consume(2);if((t[0]&48)!==0){let n=this.createError(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");e(n);return}let s=(t[0]&64)===64;if(s&&!this._extensions[Wo.extensionName]){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(this._fin=(t[0]&128)===128,this._opcode=t[0]&15,this._payloadLength=t[1]&127,this._opcode===0){if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(!this._fragmented){let n=this.createError(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}this._compressed=s}else if(this._opcode>7&&this._opcode<11){if(!this._fin){let n=this.createError(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");e(n);return}if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){let n=this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");e(n);return}}else{let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(t[1]&128)===128,this._isServer){if(!this._masked){let n=this.createError(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK");e(n);return}}else if(this._masked){let n=this.createError(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");e(n);return}this._payloadLength===126?this._state=Go:this._payloadLength===127?this._state=Vo:this.haveLength(e)}getPayloadLength16(e){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength(e)}getPayloadLength64(e){if(this._bufferedBytes<8){this._loop=!1;return}let t=this.consume(8),s=t.readUInt32BE(0);if(s>Math.pow(2,21)-1){let n=this.createError(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH");e(n);return}this._payloadLength=s*Math.pow(2,32)+t.readUInt32BE(4),this.haveLength(e)}haveLength(e){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0)){let t=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");e(t);return}this._masked?this._state=Yo:this._state=xr}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=xr}getData(e){let t=qo;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}t=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0&&vu(t,this._mask)}if(this._opcode>7){this.controlMessage(t,e);return}if(this._compressed){this._state=Sr,this.decompress(t,e);return}if(t.length){if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let s=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");e(s);return}this._messageLength=this._totalPayloadLength,this._fragments.push(t)}this.dataMessage(e)}decompress(e,t){this._extensions[Wo.extensionName].decompress(e,this._fin,(n,r)=>{if(n)return t(n);if(r.length){if(this._messageLength+=r.length,this._messageLength>this._maxPayload&&this._maxPayload>0){let i=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");t(i);return}if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let i=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");t(i);return}this._fragments.push(r)}this.dataMessage(t),this._state===ht&&this.startLoop(t)})}dataMessage(e){if(!this._fin){this._state=ht;return}let t=this._messageLength,s=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],this._opcode===2){let n;this._binaryType==="nodebuffer"?n=kr(s,t):this._binaryType==="arraybuffer"?n=yu(kr(s,t)):this._binaryType==="blob"?n=new Blob(s):n=s,this._allowSynchronousEvents?(this.emit("message",n,!0),this._state=ht):(this._state=ua,setImmediate(()=>{this.emit("message",n,!0),this._state=ht,this.startLoop(e)}))}else{let n=kr(s,t);if(!this._skipUTF8Validation&&!zo(n)){let r=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");e(r);return}this._state===Sr||this._allowSynchronousEvents?(this.emit("message",n,!1),this._state=ht):(this._state=ua,setImmediate(()=>{this.emit("message",n,!1),this._state=ht,this.startLoop(e)}))}}controlMessage(e,t){if(this._opcode===8){if(e.length===0)this._loop=!1,this.emit("conclude",1005,qo),this.end();else{let s=e.readUInt16BE(0);if(!wu(s)){let r=this.createError(RangeError,`invalid status code ${s}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");t(r);return}let n=new da(e.buffer,e.byteOffset+2,e.length-2);if(!this._skipUTF8Validation&&!zo(n)){let r=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");t(r);return}this._loop=!1,this.emit("conclude",s,n),this.end()}this._state=ht;return}this._allowSynchronousEvents?(this.emit(this._opcode===9?"ping":"pong",e),this._state=ht):(this._state=ua,setImmediate(()=>{this.emit(this._opcode===9?"ping":"pong",e),this._state=ht,this.startLoop(t)}))}createError(e,t,s,n,r){this._loop=!1,this._errored=!0;let i=new e(s?`Invalid WebSocket frame: ${t}`:t);return Error.captureStackTrace(i,this.createError),i.code=r,i[fu]=n,i}};Ko.exports=Cr});var Pr=tt((pg,Qo)=>{"use strict";var{Duplex:hg}=require("stream"),{randomFillSync:bu}=require("crypto"),{types:{isUint8Array:ku}}=require("util"),Jo=ks(),{EMPTY_BUFFER:xu,kWebSocket:Su,NOOP:Cu}=Rt(),{isBlob:Ss,isValidStatusCode:Tu}=xs(),{mask:Xo,toBuffer:ns}=Zs(),pt=Symbol("kByteLength"),_u=Buffer.alloc(4),ha=8*1024,as,Cs=ha,yt=0,Au=1,Pu=2,_r=class a{constructor(e,t,s){this._extensions=t||{},s&&(this._generateMask=s,this._maskBuffer=Buffer.alloc(4)),this._socket=e,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=yt,this.onerror=Cu,this[Su]=void 0}static frame(e,t){let s,n=!1,r=2,i=!1;t.mask&&(s=t.maskBuffer||_u,t.generateMask?t.generateMask(s):(Cs===ha&&(as===void 0&&(as=Buffer.alloc(ha)),bu(as,0,ha),Cs=0),s[0]=as[Cs++],s[1]=as[Cs++],s[2]=as[Cs++],s[3]=as[Cs++]),i=(s[0]|s[1]|s[2]|s[3])===0,r=6);let o;typeof e=="string"?(!t.mask||i)&&t[pt]!==void 0?o=t[pt]:(e=Buffer.from(e),o=e.length):(o=e.length,n=t.mask&&t.readOnly&&!i);let l=o;o>=65536?(r+=8,l=127):o>125&&(r+=2,l=126);let c=Buffer.allocUnsafe(n?o+r:r);return c[0]=t.fin?t.opcode|128:t.opcode,t.rsv1&&(c[0]|=64),c[1]=l,l===126?c.writeUInt16BE(o,2):l===127&&(c[2]=c[3]=0,c.writeUIntBE(o,4,6)),t.mask?(c[1]|=128,c[r-4]=s[0],c[r-3]=s[1],c[r-2]=s[2],c[r-1]=s[3],i?[c,e]:n?(Xo(e,s,c,r,o),[c]):(Xo(e,s,e,0,o),[c,e])):[c,e]}close(e,t,s,n){let r;if(e===void 0)r=xu;else{if(typeof e!="number"||!Tu(e))throw new TypeError("First argument must be a valid error code number");if(t===void 0||!t.length)r=Buffer.allocUnsafe(2),r.writeUInt16BE(e,0);else{let o=Buffer.byteLength(t);if(o>123)throw new RangeError("The message must not be greater than 123 bytes");if(r=Buffer.allocUnsafe(2+o),r.writeUInt16BE(e,0),typeof t=="string")r.write(t,2);else if(ku(t))r.set(t,2);else throw new TypeError("Second argument must be a string or a Uint8Array")}}let i={[pt]:r.length,fin:!0,generateMask:this._generateMask,mask:s,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};this._state!==yt?this.enqueue([this.dispatch,r,!1,i,n]):this.sendFrame(a.frame(r,i),n)}ping(e,t,s){let n,r;if(typeof e=="string"?(n=Buffer.byteLength(e),r=!1):Ss(e)?(n=e.size,r=!1):(e=ns(e),n=e.length,r=ns.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let i={[pt]:n,fin:!0,generateMask:this._generateMask,mask:t,maskBuffer:this._maskBuffer,opcode:9,readOnly:r,rsv1:!1};Ss(e)?this._state!==yt?this.enqueue([this.getBlobData,e,!1,i,s]):this.getBlobData(e,!1,i,s):this._state!==yt?this.enqueue([this.dispatch,e,!1,i,s]):this.sendFrame(a.frame(e,i),s)}pong(e,t,s){let n,r;if(typeof e=="string"?(n=Buffer.byteLength(e),r=!1):Ss(e)?(n=e.size,r=!1):(e=ns(e),n=e.length,r=ns.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let i={[pt]:n,fin:!0,generateMask:this._generateMask,mask:t,maskBuffer:this._maskBuffer,opcode:10,readOnly:r,rsv1:!1};Ss(e)?this._state!==yt?this.enqueue([this.getBlobData,e,!1,i,s]):this.getBlobData(e,!1,i,s):this._state!==yt?this.enqueue([this.dispatch,e,!1,i,s]):this.sendFrame(a.frame(e,i),s)}send(e,t,s){let n=this._extensions[Jo.extensionName],r=t.binary?2:1,i=t.compress,o,l;typeof e=="string"?(o=Buffer.byteLength(e),l=!1):Ss(e)?(o=e.size,l=!1):(e=ns(e),o=e.length,l=ns.readOnly),this._firstFragment?(this._firstFragment=!1,i&&n&&n.params[n._isServer?"server_no_context_takeover":"client_no_context_takeover"]&&(i=o>=n._threshold),this._compress=i):(i=!1,r=0),t.fin&&(this._firstFragment=!0);let c={[pt]:o,fin:t.fin,generateMask:this._generateMask,mask:t.mask,maskBuffer:this._maskBuffer,opcode:r,readOnly:l,rsv1:i};Ss(e)?this._state!==yt?this.enqueue([this.getBlobData,e,this._compress,c,s]):this.getBlobData(e,this._compress,c,s):this._state!==yt?this.enqueue([this.dispatch,e,this._compress,c,s]):this.dispatch(e,this._compress,c,s)}getBlobData(e,t,s,n){this._bufferedBytes+=s[pt],this._state=Pu,e.arrayBuffer().then(r=>{if(this._socket.destroyed){let o=new Error("The socket was closed while the blob was being read");process.nextTick(Ar,this,o,n);return}this._bufferedBytes-=s[pt];let i=ns(r);t?this.dispatch(i,t,s,n):(this._state=yt,this.sendFrame(a.frame(i,s),n),this.dequeue())}).catch(r=>{process.nextTick(Eu,this,r,n)})}dispatch(e,t,s,n){if(!t){this.sendFrame(a.frame(e,s),n);return}let r=this._extensions[Jo.extensionName];this._bufferedBytes+=s[pt],this._state=Au,r.compress(e,s.fin,(i,o)=>{if(this._socket.destroyed){let l=new Error("The socket was closed while data was being compressed");Ar(this,l,n);return}this._bufferedBytes-=s[pt],this._state=yt,s.readOnly=!1,this.sendFrame(a.frame(o,s),n),this.dequeue()})}dequeue(){for(;this._state===yt&&this._queue.length;){let e=this._queue.shift();this._bufferedBytes-=e[3][pt],Reflect.apply(e[0],this,e.slice(1))}}enqueue(e){this._bufferedBytes+=e[3][pt],this._queue.push(e)}sendFrame(e,t){e.length===2?(this._socket.cork(),this._socket.write(e[0]),this._socket.write(e[1],t),this._socket.uncork()):this._socket.write(e[0],t)}};Qo.exports=_r;function Ar(a,e,t){typeof t=="function"&&t(e);for(let s=0;s<a._queue.length;s++){let n=a._queue[s],r=n[n.length-1];typeof r=="function"&&r(e)}}function Eu(a,e,t){Ar(a,e,t),a.onerror(e)}});var ol=tt((mg,il)=>{"use strict";var{kForOnEventAttribute:tn,kListener:Er}=Rt(),Zo=Symbol("kCode"),el=Symbol("kData"),tl=Symbol("kError"),sl=Symbol("kMessage"),nl=Symbol("kReason"),Ts=Symbol("kTarget"),al=Symbol("kType"),rl=Symbol("kWasClean"),Mt=class{constructor(e){this[Ts]=null,this[al]=e}get target(){return this[Ts]}get type(){return this[al]}};Object.defineProperty(Mt.prototype,"target",{enumerable:!0});Object.defineProperty(Mt.prototype,"type",{enumerable:!0});var rs=class extends Mt{constructor(e,t={}){super(e),this[Zo]=t.code===void 0?0:t.code,this[nl]=t.reason===void 0?"":t.reason,this[rl]=t.wasClean===void 0?!1:t.wasClean}get code(){return this[Zo]}get reason(){return this[nl]}get wasClean(){return this[rl]}};Object.defineProperty(rs.prototype,"code",{enumerable:!0});Object.defineProperty(rs.prototype,"reason",{enumerable:!0});Object.defineProperty(rs.prototype,"wasClean",{enumerable:!0});var _s=class extends Mt{constructor(e,t={}){super(e),this[tl]=t.error===void 0?null:t.error,this[sl]=t.message===void 0?"":t.message}get error(){return this[tl]}get message(){return this[sl]}};Object.defineProperty(_s.prototype,"error",{enumerable:!0});Object.defineProperty(_s.prototype,"message",{enumerable:!0});var sn=class extends Mt{constructor(e,t={}){super(e),this[el]=t.data===void 0?null:t.data}get data(){return this[el]}};Object.defineProperty(sn.prototype,"data",{enumerable:!0});var Du={addEventListener(a,e,t={}){for(let n of this.listeners(a))if(!t[tn]&&n[Er]===e&&!n[tn])return;let s;if(a==="message")s=function(r,i){let o=new sn("message",{data:i?r:r.toString()});o[Ts]=this,pa(e,this,o)};else if(a==="close")s=function(r,i){let o=new rs("close",{code:r,reason:i.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});o[Ts]=this,pa(e,this,o)};else if(a==="error")s=function(r){let i=new _s("error",{error:r,message:r.message});i[Ts]=this,pa(e,this,i)};else if(a==="open")s=function(){let r=new Mt("open");r[Ts]=this,pa(e,this,r)};else return;s[tn]=!!t[tn],s[Er]=e,t.once?this.once(a,s):this.on(a,s)},removeEventListener(a,e){for(let t of this.listeners(a))if(t[Er]===e&&!t[tn]){this.removeListener(a,t);break}}};il.exports={CloseEvent:rs,ErrorEvent:_s,Event:Mt,EventTarget:Du,MessageEvent:sn};function pa(a,e,t){typeof a=="object"&&a.handleEvent?a.handleEvent.call(a,t):a.call(e,t)}});var ma=tt((fg,ll)=>{"use strict";var{tokenChars:nn}=xs();function St(a,e,t){a[e]===void 0?a[e]=[t]:a[e].push(t)}function Ru(a){let e=Object.create(null),t=Object.create(null),s=!1,n=!1,r=!1,i,o,l=-1,c=-1,d=-1,u=0;for(;u<a.length;u++)if(c=a.charCodeAt(u),i===void 0)if(d===-1&&nn[c]===1)l===-1&&(l=u);else if(u!==0&&(c===32||c===9))d===-1&&l!==-1&&(d=u);else if(c===59||c===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${u}`);d===-1&&(d=u);let p=a.slice(l,d);c===44?(St(e,p,t),t=Object.create(null)):i=p,l=d=-1}else throw new SyntaxError(`Unexpected character at index ${u}`);else if(o===void 0)if(d===-1&&nn[c]===1)l===-1&&(l=u);else if(c===32||c===9)d===-1&&l!==-1&&(d=u);else if(c===59||c===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${u}`);d===-1&&(d=u),St(t,a.slice(l,d),!0),c===44&&(St(e,i,t),t=Object.create(null),i=void 0),l=d=-1}else if(c===61&&l!==-1&&d===-1)o=a.slice(l,u),l=d=-1;else throw new SyntaxError(`Unexpected character at index ${u}`);else if(n){if(nn[c]!==1)throw new SyntaxError(`Unexpected character at index ${u}`);l===-1?l=u:s||(s=!0),n=!1}else if(r)if(nn[c]===1)l===-1&&(l=u);else if(c===34&&l!==-1)r=!1,d=u;else if(c===92)n=!0;else throw new SyntaxError(`Unexpected character at index ${u}`);else if(c===34&&a.charCodeAt(u-1)===61)r=!0;else if(d===-1&&nn[c]===1)l===-1&&(l=u);else if(l!==-1&&(c===32||c===9))d===-1&&(d=u);else if(c===59||c===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${u}`);d===-1&&(d=u);let p=a.slice(l,d);s&&(p=p.replace(/\\/g,""),s=!1),St(t,o,p),c===44&&(St(e,i,t),t=Object.create(null),i=void 0),o=void 0,l=d=-1}else throw new SyntaxError(`Unexpected character at index ${u}`);if(l===-1||r||c===32||c===9)throw new SyntaxError("Unexpected end of input");d===-1&&(d=u);let h=a.slice(l,d);return i===void 0?St(e,h,t):(o===void 0?St(t,h,!0):s?St(t,o,h.replace(/\\/g,"")):St(t,o,h),St(e,i,t)),e}function Iu(a){return Object.keys(a).map(e=>{let t=a[e];return Array.isArray(t)||(t=[t]),t.map(s=>[e].concat(Object.keys(s).map(n=>{let r=s[n];return Array.isArray(r)||(r=[r]),r.map(i=>i===!0?n:`${n}=${i}`).join("; ")})).join("; ")).join(", ")}).join(", ")}ll.exports={format:Iu,parse:Ru}});var va=tt((vg,bl)=>{"use strict";var Mu=require("events"),Fu=require("https"),Lu=require("http"),ul=require("net"),Ou=require("tls"),{randomBytes:Nu,createHash:Bu}=require("crypto"),{Duplex:gg,Readable:yg}=require("stream"),{URL:Dr}=require("url"),jt=ks(),Uu=Tr(),$u=Pr(),{isBlob:ju}=xs(),{BINARY_TYPES:cl,CLOSE_TIMEOUT:Hu,EMPTY_BUFFER:fa,GUID:Wu,kForOnEventAttribute:Rr,kListener:qu,kStatusCode:zu,kWebSocket:Me,NOOP:hl}=Rt(),{EventTarget:{addEventListener:Gu,removeEventListener:Vu}}=ol(),{format:Yu,parse:Ku}=ma(),{toBuffer:Ju}=Zs(),pl=Symbol("kAborted"),Ir=[8,13],Ft=["CONNECTING","OPEN","CLOSING","CLOSED"],Xu=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/,he=class a extends Mu{constructor(e,t,s){super(),this._binaryType=cl[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=fa,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol="",this._readyState=a.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,e!==null?(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,t===void 0?t=[]:Array.isArray(t)||(typeof t=="object"&&t!==null?(s=t,t=[]):t=[t]),ml(this,e,t,s)):(this._autoPong=s.autoPong,this._closeTimeout=s.closeTimeout,this._isServer=!0)}get binaryType(){return this._binaryType}set binaryType(e){cl.includes(e)&&(this._binaryType=e,this._receiver&&(this._receiver._binaryType=e))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(e,t,s){let n=new Uu({allowSynchronousEvents:s.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxBufferedChunks:s.maxBufferedChunks,maxFragments:s.maxFragments,maxPayload:s.maxPayload,skipUTF8Validation:s.skipUTF8Validation}),r=new $u(e,this._extensions,s.generateMask);this._receiver=n,this._sender=r,this._socket=e,n[Me]=this,r[Me]=this,e[Me]=this,n.on("conclude",eh),n.on("drain",th),n.on("error",sh),n.on("message",nh),n.on("ping",ah),n.on("pong",rh),r.onerror=ih,e.setTimeout&&e.setTimeout(0),e.setNoDelay&&e.setNoDelay(),t.length>0&&e.unshift(t),e.on("close",yl),e.on("data",ya),e.on("end",vl),e.on("error",wl),this._readyState=a.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=a.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}this._extensions[jt.extensionName]&&this._extensions[jt.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=a.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(e,t){if(this.readyState!==a.CLOSED){if(this.readyState===a.CONNECTING){it(this,this._req,"WebSocket was closed before the connection was established");return}if(this.readyState===a.CLOSING){this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end();return}this._readyState=a.CLOSING,this._sender.close(e,t,!this._isServer,s=>{s||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())}),gl(this)}}pause(){this.readyState===a.CONNECTING||this.readyState===a.CLOSED||(this._paused=!0,this._socket.pause())}ping(e,t,s){if(this.readyState===a.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(s=e,e=t=void 0):typeof t=="function"&&(s=t,t=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==a.OPEN){Mr(this,e,s);return}t===void 0&&(t=!this._isServer),this._sender.ping(e||fa,t,s)}pong(e,t,s){if(this.readyState===a.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(s=e,e=t=void 0):typeof t=="function"&&(s=t,t=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==a.OPEN){Mr(this,e,s);return}t===void 0&&(t=!this._isServer),this._sender.pong(e||fa,t,s)}resume(){this.readyState===a.CONNECTING||this.readyState===a.CLOSED||(this._paused=!1,this._receiver._writableState.needDrain||this._socket.resume())}send(e,t,s){if(this.readyState===a.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof t=="function"&&(s=t,t={}),typeof e=="number"&&(e=e.toString()),this.readyState!==a.OPEN){Mr(this,e,s);return}let n={binary:typeof e!="string",mask:!this._isServer,compress:!0,fin:!0,...t};this._extensions[jt.extensionName]||(n.compress=!1),this._sender.send(e||fa,n,s)}terminate(){if(this.readyState!==a.CLOSED){if(this.readyState===a.CONNECTING){it(this,this._req,"WebSocket was closed before the connection was established");return}this._socket&&(this._readyState=a.CLOSING,this._socket.destroy())}}};Object.defineProperty(he,"CONNECTING",{enumerable:!0,value:Ft.indexOf("CONNECTING")});Object.defineProperty(he.prototype,"CONNECTING",{enumerable:!0,value:Ft.indexOf("CONNECTING")});Object.defineProperty(he,"OPEN",{enumerable:!0,value:Ft.indexOf("OPEN")});Object.defineProperty(he.prototype,"OPEN",{enumerable:!0,value:Ft.indexOf("OPEN")});Object.defineProperty(he,"CLOSING",{enumerable:!0,value:Ft.indexOf("CLOSING")});Object.defineProperty(he.prototype,"CLOSING",{enumerable:!0,value:Ft.indexOf("CLOSING")});Object.defineProperty(he,"CLOSED",{enumerable:!0,value:Ft.indexOf("CLOSED")});Object.defineProperty(he.prototype,"CLOSED",{enumerable:!0,value:Ft.indexOf("CLOSED")});["binaryType","bufferedAmount","extensions","isPaused","protocol","readyState","url"].forEach(a=>{Object.defineProperty(he.prototype,a,{enumerable:!0})});["open","error","close","message"].forEach(a=>{Object.defineProperty(he.prototype,`on${a}`,{enumerable:!0,get(){for(let e of this.listeners(a))if(e[Rr])return e[qu];return null},set(e){for(let t of this.listeners(a))if(t[Rr]){this.removeListener(a,t);break}typeof e=="function"&&this.addEventListener(a,e,{[Rr]:!0})}})});he.prototype.addEventListener=Gu;he.prototype.removeEventListener=Vu;bl.exports=he;function ml(a,e,t,s){let n={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:Hu,protocolVersion:Ir[1],maxBufferedChunks:1048576,maxFragments:131072,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...s,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:"GET",host:void 0,path:void 0,port:void 0};if(a._autoPong=n.autoPong,a._closeTimeout=n.closeTimeout,!Ir.includes(n.protocolVersion))throw new RangeError(`Unsupported protocol version: ${n.protocolVersion} (supported versions: ${Ir.join(", ")})`);let r;if(e instanceof Dr)r=e;else try{r=new Dr(e)}catch{throw new SyntaxError(`Invalid URL: ${e}`)}r.protocol==="http:"?r.protocol="ws:":r.protocol==="https:"&&(r.protocol="wss:"),a._url=r.href;let i=r.protocol==="wss:",o=r.protocol==="ws+unix:",l;if(r.protocol!=="ws:"&&!i&&!o?l=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`:o&&!r.pathname?l="The URL's pathname is empty":r.hash&&(l="The URL contains a fragment identifier"),l){let f=new SyntaxError(l);if(a._redirects===0)throw f;ga(a,f);return}let c=i?443:80,d=Nu(16).toString("base64"),u=i?Fu.request:Lu.request,h=new Set,p;if(n.createConnection=n.createConnection||(i?Zu:Qu),n.defaultPort=n.defaultPort||c,n.port=r.port||c,n.host=r.hostname.startsWith("[")?r.hostname.slice(1,-1):r.hostname,n.headers={...n.headers,"Sec-WebSocket-Version":n.protocolVersion,"Sec-WebSocket-Key":d,Connection:"Upgrade",Upgrade:"websocket"},n.path=r.pathname+r.search,n.timeout=n.handshakeTimeout,n.perMessageDeflate&&(p=new jt({...n.perMessageDeflate,isServer:!1,maxPayload:n.maxPayload}),n.headers["Sec-WebSocket-Extensions"]=Yu({[jt.extensionName]:p.offer()})),t.length){for(let f of t){if(typeof f!="string"||!Xu.test(f)||h.has(f))throw new SyntaxError("An invalid or duplicated subprotocol was specified");h.add(f)}n.headers["Sec-WebSocket-Protocol"]=t.join(",")}if(n.origin&&(n.protocolVersion<13?n.headers["Sec-WebSocket-Origin"]=n.origin:n.headers.Origin=n.origin),(r.username||r.password)&&(n.auth=`${r.username}:${r.password}`),o){let f=n.path.split(":");n.socketPath=f[0],n.path=f[1]}let m;if(n.followRedirects){if(a._redirects===0){a._originalIpc=o,a._originalSecure=i,a._originalHostOrSocketPath=o?n.socketPath:r.host;let f=s&&s.headers;if(s={...s,headers:{}},f)for(let[g,w]of Object.entries(f))s.headers[g.toLowerCase()]=w}else if(a.listenerCount("redirect")===0){let f=o?a._originalIpc?n.socketPath===a._originalHostOrSocketPath:!1:a._originalIpc?!1:r.host===a._originalHostOrSocketPath;(!f||a._originalSecure&&!i)&&(delete n.headers.authorization,delete n.headers.cookie,f||delete n.headers.host,n.auth=void 0)}n.auth&&!s.headers.authorization&&(s.headers.authorization="Basic "+Buffer.from(n.auth).toString("base64")),m=a._req=u(n),a._redirects&&a.emit("redirect",a.url,m)}else m=a._req=u(n);n.timeout&&m.on("timeout",()=>{it(a,m,"Opening handshake has timed out")}),m.on("error",f=>{m===null||m[pl]||(m=a._req=null,ga(a,f))}),m.on("response",f=>{let g=f.headers.location,w=f.statusCode;if(g&&n.followRedirects&&w>=300&&w<400){if(++a._redirects>n.maxRedirects){it(a,m,"Maximum redirects exceeded");return}m.abort();let y;try{y=new Dr(g,e)}catch{let k=new SyntaxError(`Invalid URL: ${g}`);ga(a,k);return}ml(a,y,t,s)}else a.emit("unexpected-response",m,f)||it(a,m,`Unexpected server response: ${f.statusCode}`)}),m.on("upgrade",(f,g,w)=>{if(a.emit("upgrade",f),a.readyState!==he.CONNECTING)return;m=a._req=null;let y=f.headers.upgrade;if(y===void 0||y.toLowerCase()!=="websocket"){it(a,g,"Invalid Upgrade header");return}let v=Bu("sha1").update(d+Wu).digest("base64");if(f.headers["sec-websocket-accept"]!==v){it(a,g,"Invalid Sec-WebSocket-Accept header");return}let k=f.headers["sec-websocket-protocol"],b;if(k!==void 0?h.size?h.has(k)||(b="Server sent an invalid subprotocol"):b="Server sent a subprotocol but none was requested":h.size&&(b="Server sent no subprotocol"),b){it(a,g,b);return}k&&(a._protocol=k);let P=f.headers["sec-websocket-extensions"];if(P!==void 0){if(!p){it(a,g,"Server sent a Sec-WebSocket-Extensions header but no extension was requested");return}let A;try{A=Ku(P)}catch{it(a,g,"Invalid Sec-WebSocket-Extensions header");return}let M=Object.keys(A);if(M.length!==1||M[0]!==jt.extensionName){it(a,g,"Server indicated an extension that was not requested");return}try{p.accept(A[jt.extensionName])}catch{it(a,g,"Invalid Sec-WebSocket-Extensions header");return}a._extensions[jt.extensionName]=p}a.setSocket(g,w,{allowSynchronousEvents:n.allowSynchronousEvents,generateMask:n.generateMask,maxBufferedChunks:n.maxBufferedChunks,maxFragments:n.maxFragments,maxPayload:n.maxPayload,skipUTF8Validation:n.skipUTF8Validation})}),n.finishRequest?n.finishRequest(m,a):m.end()}function ga(a,e){a._readyState=he.CLOSING,a._errorEmitted=!0,a.emit("error",e),a.emitClose()}function Qu(a){return a.path=a.socketPath,ul.connect(a)}function Zu(a){return a.path=void 0,!a.servername&&a.servername!==""&&(a.servername=ul.isIP(a.host)?"":a.host),Ou.connect(a)}function it(a,e,t){a._readyState=he.CLOSING;let s=new Error(t);Error.captureStackTrace(s,it),e.setHeader?(e[pl]=!0,e.abort(),e.socket&&!e.socket.destroyed&&e.socket.destroy(),process.nextTick(ga,a,s)):(e.destroy(s),e.once("error",a.emit.bind(a,"error")),e.once("close",a.emitClose.bind(a)))}function Mr(a,e,t){if(e){let s=ju(e)?e.size:Ju(e).length;a._socket?a._sender._bufferedBytes+=s:a._bufferedAmount+=s}if(t){let s=new Error(`WebSocket is not open: readyState ${a.readyState} (${Ft[a.readyState]})`);process.nextTick(t,s)}}function eh(a,e){let t=this[Me];t._closeFrameReceived=!0,t._closeMessage=e,t._closeCode=a,t._socket[Me]!==void 0&&(t._socket.removeListener("data",ya),process.nextTick(fl,t._socket),a===1005?t.close():t.close(a,e))}function th(){let a=this[Me];a.isPaused||a._socket.resume()}function sh(a){let e=this[Me];e._socket[Me]!==void 0&&(e._socket.removeListener("data",ya),process.nextTick(fl,e._socket),e.close(a[zu])),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",a))}function dl(){this[Me].emitClose()}function nh(a,e){this[Me].emit("message",a,e)}function ah(a){let e=this[Me];e._autoPong&&e.pong(a,!this._isServer,hl),e.emit("ping",a)}function rh(a){this[Me].emit("pong",a)}function fl(a){a.resume()}function ih(a){let e=this[Me];e.readyState!==he.CLOSED&&(e.readyState===he.OPEN&&(e._readyState=he.CLOSING,gl(e)),this._socket.end(),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",a)))}function gl(a){a._closeTimer=setTimeout(a._socket.destroy.bind(a._socket),a._closeTimeout)}function yl(){let a=this[Me];if(this.removeListener("close",yl),this.removeListener("data",ya),this.removeListener("end",vl),a._readyState=he.CLOSING,!this._readableState.endEmitted&&!a._closeFrameReceived&&!a._receiver._writableState.errorEmitted&&this._readableState.length!==0){let e=this.read(this._readableState.length);a._receiver.write(e)}a._receiver.end(),this[Me]=void 0,clearTimeout(a._closeTimer),a._receiver._writableState.finished||a._receiver._writableState.errorEmitted?a.emitClose():(a._receiver.on("error",dl),a._receiver.on("finish",dl))}function ya(a){this[Me]._receiver.write(a)||this.pause()}function vl(){let a=this[Me];a._readyState=he.CLOSING,a._receiver.end(),this.end()}function wl(){let a=this[Me];this.removeListener("error",wl),this.on("error",hl),a&&(a._readyState=he.CLOSING,this.destroy())}});var Cl=tt((bg,Sl)=>{"use strict";var wg=va(),{Duplex:oh}=require("stream");function kl(a){a.emit("close")}function lh(){!this.destroyed&&this._writableState.finished&&this.destroy()}function xl(a){this.removeListener("error",xl),this.destroy(),this.listenerCount("error")===0&&this.emit("error",a)}function ch(a,e){let t=!0,s=new oh({...e,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return a.on("message",function(r,i){let o=!i&&s._readableState.objectMode?r.toString():r;s.push(o)||a.pause()}),a.once("error",function(r){s.destroyed||(t=!1,s.destroy(r))}),a.once("close",function(){s.destroyed||s.push(null)}),s._destroy=function(n,r){if(a.readyState===a.CLOSED){r(n),process.nextTick(kl,s);return}let i=!1;a.once("error",function(l){i=!0,r(l)}),a.once("close",function(){i||r(n),process.nextTick(kl,s)}),t&&a.terminate()},s._final=function(n){if(a.readyState===a.CONNECTING){a.once("open",function(){s._final(n)});return}a._socket!==null&&(a._socket._writableState.finished?(n(),s._readableState.endEmitted&&s.destroy()):(a._socket.once("finish",function(){n()}),a.close()))},s._read=function(){a.isPaused&&a.resume()},s._write=function(n,r,i){if(a.readyState===a.CONNECTING){a.once("open",function(){s._write(n,r,i)});return}a.send(n,i)},s.on("end",lh),s.on("error",xl),s}Sl.exports=ch});var Fr=tt((kg,Tl)=>{"use strict";var{tokenChars:dh}=xs();function uh(a){let e=new Set,t=-1,s=-1,n=0;for(n;n<a.length;n++){let i=a.charCodeAt(n);if(s===-1&&dh[i]===1)t===-1&&(t=n);else if(n!==0&&(i===32||i===9))s===-1&&t!==-1&&(s=n);else if(i===44){if(t===-1)throw new SyntaxError(`Unexpected character at index ${n}`);s===-1&&(s=n);let o=a.slice(t,s);if(e.has(o))throw new SyntaxError(`The "${o}" subprotocol is duplicated`);e.add(o),t=s=-1}else throw new SyntaxError(`Unexpected character at index ${n}`)}if(t===-1||s!==-1)throw new SyntaxError("Unexpected end of input");let r=a.slice(t,n);if(e.has(r))throw new SyntaxError(`The "${r}" subprotocol is duplicated`);return e.add(r),e}Tl.exports={parse:uh}});var Il=tt((Sg,Rl)=>{"use strict";var hh=require("events"),wa=require("http"),{Duplex:xg}=require("stream"),{createHash:ph}=require("crypto"),_l=ma(),is=ks(),mh=Fr(),fh=va(),{CLOSE_TIMEOUT:gh,GUID:yh,kWebSocket:vh}=Rt(),wh=/^[+/0-9A-Za-z]{22}==$/,Al=0,Pl=1,Dl=2,Lr=class extends hh{constructor(e,t){if(super(),e={allowSynchronousEvents:!0,autoPong:!0,maxBufferedChunks:1024*1024,maxFragments:128*1024,maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:gh,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:fh,...e},e.port==null&&!e.server&&!e.noServer||e.port!=null&&(e.server||e.noServer)||e.server&&e.noServer)throw new TypeError('One and only one of the "port", "server", or "noServer" options must be specified');if(e.port!=null?(this._server=wa.createServer((s,n)=>{let r=wa.STATUS_CODES[426];n.writeHead(426,{"Content-Length":r.length,"Content-Type":"text/plain"}),n.end(r)}),this._server.listen(e.port,e.host,e.backlog,t)):e.server&&(this._server=e.server),this._server){let s=this.emit.bind(this,"connection");this._removeListeners=bh(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(n,r,i)=>{this.handleUpgrade(n,r,i,s)}})}e.perMessageDeflate===!0&&(e.perMessageDeflate={}),e.clientTracking&&(this.clients=new Set,this._shouldEmitClose=!1),this.options=e,this._state=Al}address(){if(this.options.noServer)throw new Error('The server is operating in "noServer" mode');return this._server?this._server.address():null}close(e){if(this._state===Dl){e&&this.once("close",()=>{e(new Error("The server is not running"))}),process.nextTick(an,this);return}if(e&&this.once("close",e),this._state!==Pl)if(this._state=Pl,this.options.noServer||this.options.server)this._server&&(this._removeListeners(),this._removeListeners=this._server=null),this.clients?this.clients.size?this._shouldEmitClose=!0:process.nextTick(an,this):process.nextTick(an,this);else{let t=this._server;this._removeListeners(),this._removeListeners=this._server=null,t.close(()=>{an(this)})}}shouldHandle(e){if(this.options.path){let t=e.url.indexOf("?");if((t!==-1?e.url.slice(0,t):e.url)!==this.options.path)return!1}return!0}handleUpgrade(e,t,s,n){t.on("error",El);let r=e.headers["sec-websocket-key"],i=e.headers.upgrade,o=+e.headers["sec-websocket-version"];if(e.method!=="GET"){os(this,e,t,405,"Invalid HTTP method");return}if(i===void 0||i.toLowerCase()!=="websocket"){os(this,e,t,400,"Invalid Upgrade header");return}if(r===void 0||!wh.test(r)){os(this,e,t,400,"Missing or invalid Sec-WebSocket-Key header");return}if(o!==13&&o!==8){os(this,e,t,400,"Missing or invalid Sec-WebSocket-Version header",{"Sec-WebSocket-Version":"13, 8"});return}if(!this.shouldHandle(e)){rn(t,400);return}let l=e.headers["sec-websocket-protocol"],c=new Set;if(l!==void 0)try{c=mh.parse(l)}catch{os(this,e,t,400,"Invalid Sec-WebSocket-Protocol header");return}let d=e.headers["sec-websocket-extensions"],u={};if(this.options.perMessageDeflate&&d!==void 0){let h=new is({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let p=_l.parse(d);p[is.extensionName]&&(h.accept(p[is.extensionName]),u[is.extensionName]=h)}catch{os(this,e,t,400,"Invalid or unacceptable Sec-WebSocket-Extensions header");return}}if(this.options.verifyClient){let h={origin:e.headers[`${o===8?"sec-websocket-origin":"origin"}`],secure:!!(e.socket.authorized||e.socket.encrypted),req:e};if(this.options.verifyClient.length===2){this.options.verifyClient(h,(p,m,f,g)=>{if(!p)return rn(t,m||401,f,g);this.completeUpgrade(u,r,c,e,t,s,n)});return}if(!this.options.verifyClient(h))return rn(t,401)}this.completeUpgrade(u,r,c,e,t,s,n)}completeUpgrade(e,t,s,n,r,i,o){if(!r.readable||!r.writable)return r.destroy();if(r[vh])throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");if(this._state>Al)return rn(r,503);let c=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${ph("sha1").update(t+yh).digest("base64")}`],d=new this.options.WebSocket(null,void 0,this.options);if(s.size){let u=this.options.handleProtocols?this.options.handleProtocols(s,n):s.values().next().value;u&&(c.push(`Sec-WebSocket-Protocol: ${u}`),d._protocol=u)}if(e[is.extensionName]){let u=e[is.extensionName].params,h=_l.format({[is.extensionName]:[u]});c.push(`Sec-WebSocket-Extensions: ${h}`),d._extensions=e}this.emit("headers",c,n),r.write(c.concat(`\r
|
|
2
2
|
`).join(`\r
|
|
3
|
-
`)),
|
|
3
|
+
`)),r.removeListener("error",El),d.setSocket(r,i,{allowSynchronousEvents:this.options.allowSynchronousEvents,maxBufferedChunks:this.options.maxBufferedChunks,maxFragments:this.options.maxFragments,maxPayload:this.options.maxPayload,skipUTF8Validation:this.options.skipUTF8Validation}),this.clients&&(this.clients.add(d),d.on("close",()=>{this.clients.delete(d),this._shouldEmitClose&&!this.clients.size&&process.nextTick(an,this)})),o(d,n)}};Rl.exports=Lr;function bh(a,e){for(let t of Object.keys(e))a.on(t,e[t]);return function(){for(let s of Object.keys(e))a.removeListener(s,e[s])}}function an(a){a._state=Dl,a.emit("close")}function El(){this.destroy()}function rn(a,e,t,s){t=t||wa.STATUS_CODES[e],s={Connection:"close","Content-Type":"text/html","Content-Length":Buffer.byteLength(t),...s},a.once("finish",a.destroy),a.end(`HTTP/1.1 ${e} ${wa.STATUS_CODES[e]}\r
|
|
4
4
|
`+Object.keys(s).map(n=>`${n}: ${s[n]}`).join(`\r
|
|
5
5
|
`)+`\r
|
|
6
6
|
\r
|
|
7
|
-
`+
|
|
7
|
+
`+t)}function os(a,e,t,s,n,r){if(a.listenerCount("wsClientError")){let i=new Error(n);Error.captureStackTrace(i,os),a.emit("wsClientError",i,t,e)}else rn(t,s,n,r)}});var bp={};jc(bp,{default:()=>Ra});module.exports=Hc(bp);var hn=require("fs"),Ms=require("fs/promises"),pn=require("os"),Is=require("path"),pe=require("obsidian");var us="agent-fleet-agents";var Yt="agent-fleet-dashboard",mt="agent-fleet-chat",ft={fleetFolder:"_fleet",claudeCliPath:"claude",codexCliPath:"codex",defaultModel:"default",awsRegion:"us-east-1",maxConcurrentRuns:2,runLogRetentionDays:30,catchUpMissedTasks:!0,notificationLevel:"all",showStatusBar:!0,mcpApiKeys:{},mcpTokens:{},channelCredentials:{},maxConcurrentChannelSessions:5,channelIdleTimeoutMinutes:15,channelRateLimitPerConversation:20,channelRateLimitWindowMinutes:5,chatWatchdogMinutes:10,defaultFileHashes:{}},Xr=["agents","skills","tasks","runs","memory","channels","mcp","usage"],bn=1500,Qr="0 3 * * *",Zr=3;var Et=require("obsidian");var Ls=[{path:"agents/fleet-orchestrator/CONTEXT.md",content:`---
|
|
8
8
|
{}
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -704,6 +704,7 @@ Discord uses the Gateway (outbound WebSocket) + REST. Features: \`@agent-name\`
|
|
|
704
704
|
- Agents with \`approval_required\` set cannot be bound to a channel
|
|
705
705
|
- Multi-agent routing: type \`@agent-name: message\` to switch agents, or use \`/agents\` for interactive picker
|
|
706
706
|
- Obsidian must be running for channels to work \u2014 when closed, bots go offline
|
|
707
|
+
- Live follow-ups (since 0.15.0): a message sent while the agent is still working is folded into the running turn (Claude: live stdin; Codex: queued follow-up turn) instead of waiting for a fresh turn \u2014 matching the in-app chat. Each injected follow-up gets its own reply; \`[REMEMBER]\` blocks are stripped from channel replies.
|
|
707
708
|
|
|
708
709
|
## Creating a Task
|
|
709
710
|
|
|
@@ -11629,50 +11630,13 @@ python scripts/office/validate.py <path> [--original <original_file>] [--auto-re
|
|
|
11629
11630
|
|
|
11630
11631
|
- \`paraId\`/\`durableId\` values that exceed OOXML limits
|
|
11631
11632
|
- Missing \`xml:space="preserve"\` on \`w:t\` elements with whitespace
|
|
11632
|
-
`}];var
|
|
11633
|
-
${
|
|
11633
|
+
`}];var hs=require("obsidian");function Tt(a){return typeof a=="object"&&a!==null}function C(a){return typeof a=="string"?a:void 0}function Ie(a,e){return typeof a=="boolean"?a:e}function Pe(a,e){return typeof a=="number"&&Number.isFinite(a)?a:e}function Q(a){return Array.isArray(a)?a.filter(e=>typeof e=="string"):[]}function Na(a){if(!Tt(a))return;let e={};for(let[t,s]of Object.entries(a))typeof s=="string"&&(e[t]=s);return Object.keys(e).length>0?e:void 0}async function fe(a,e){if(!a.getAbstractFileByPath(e))try{await a.createFolder(e)}catch(t){if(!(t instanceof Error?t.message:String(t)).includes("Folder already exists"))throw t}}async function We(a,e,t){if(!a.getAbstractFileByPath(e))try{await a.create(e,t)}catch(s){if(!(s instanceof Error?s.message:String(s)).includes("File already exists"))throw s}}async function qe(a,e){let t=a.vault.getAbstractFileByPath(e);t&&await a.fileManager.trashFile(t)}function ps(a,e){for(let t of a.children)t instanceof hs.TFile&&t.extension==="md"&&e.push(t),t instanceof hs.TFolder&&ps(t,e)}async function _t(a,e,t){let s=0;for(;;){let n=s===0?"":`-${s+1}`,r=(0,hs.normalizePath)(`${e}/${t}${n}.md`);if(!a.getAbstractFileByPath(r))return r;s+=1}}var nt=require("obsidian");var kn=require("obsidian");function W(a){let e=a.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!e)return{frontmatter:{},body:a.trim()};let t=e[1]??"",s=e[2]??"",n;try{n=(0,kn.parseYaml)(t)??{}}catch(r){console.warn("Agent Fleet: malformed YAML frontmatter, treating as empty",r),n={}}return{frontmatter:n,body:s.trim()}}function U(a,e){let t=(0,kn.stringifyYaml)(a).trim(),s=e.trim();return`---
|
|
11634
|
+
${t}
|
|
11634
11635
|
---
|
|
11635
11636
|
|
|
11636
11637
|
${s}
|
|
11637
|
-
`}function oe(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")}function Wt(r,t){return r.length<=t?r:`${r.slice(0,t-1)}\u2026`}var Hs=2,dr=["Preferences","Procedures","Observations","Recent"],hr="Recent",Qn=/\[REMEMBER(?::([a-zA-Z]+))?\]([\s\S]*?)\[\/REMEMBER\]/g;function ul(r){switch((r??"").toLowerCase()){case"pin":case"preference":case"preferences":return{pinned:!0,section:"Preferences"};case"procedure":case"procedures":return{pinned:!1,section:"Procedures"};case"observation":case"observations":return{pinned:!1,section:"Observations"};default:return{pinned:!1}}}function qs(r){let t=[];for(let e of r.matchAll(Qn)){let s=(e[2]??"").trim();if(!s)continue;let n=ul(e[1]);t.push({text:s,pinned:n.pinned,section:n.section})}return t}function At(r){return r.replace(Qn,"").replace(/[ \t]+\n/g,`
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
`).trim()}function ur(r){let t=r.replace(Qn,""),e=t.match(/\[REMEMBER(?::[a-zA-Z]+)?\][\s\S]*$/i);if(e&&e.index!==void 0)return t.slice(0,e.index);let s=t.match(/\[(?:R(?:E(?:M(?:E(?:M(?:B(?:E(?:R(?::[a-zA-Z]*)?)?)?)?)?)?)?)?)?$/i);return s&&s.index!==void 0?t.slice(0,s.index):t}var pl={Preferences:"Preferences",Procedures:"Procedures",Observations:"Observations",Recent:"Recent (uncurated)"};function ml(r){let t=r.trim().toLowerCase();return t.startsWith("preference")?"Preferences":t.startsWith("procedure")?"Procedures":t.startsWith("observation")?"Observations":t.startsWith("recent")?"Recent":"Observations"}function us(r){return Math.ceil(r.length/4)}var lr=500;function pr(r){let t=r.replace(/\s+/g," ").trim();return t.length<=lr?t:`${t.slice(0,lr-1).trimEnd()}\u2026`}function Xn(r){return typeof r=="string"?r:void 0}function fl(r,t){return typeof r=="number"&&Number.isFinite(r)?r:t}function mr(r,t){return{filePath:r,agent:t,schema:Hs,tokenEstimate:0,sections:[]}}var gl=/\s*<!--\s*([\s\S]*?)\s*-->\s*$/,cr=/^\[pin\]\s+/i;function yl(r){let t=r.match(/^[-*]\s+(.*)$/);if(!t)return null;let e=(t[1]??"").trim();if(!e)return null;let s,n,a=e.match(gl);if(a){e=e.slice(0,a.index).trim();let o=(a[1]??"").trim(),c=o.match(/^src:(\S+)(?:\s+(.+))?$/);c?(s=c[1],n=c[2]?.trim()||void 0):o&&(n=o)}let i=!1;return cr.test(e)&&(i=!0,e=e.replace(cr,"").trim()),e?{text:e,source:s,date:n,pinned:i}:null}function fr(r){let t=r.pinned?"[pin] ":"",e="";if(r.source||r.date){let s=[];r.source&&s.push(`src:${r.source}`),r.date&&s.push(r.date),e=` <!-- ${s.join(" ")} -->`}return`- ${t}${r.text}${e}`}function Ke(r){return vl(r).map(e=>{let s=e.entries.map(fr).join(`
|
|
11641
|
-
`);return`## ${pl[e.name]}
|
|
11642
|
-
${s}`}).join(`
|
|
11643
|
-
|
|
11644
|
-
`)}function vl(r){let t=[];for(let e of dr){let s=r.find(n=>n.name===e);s&&s.entries.length>0&&t.push(s)}return t}function gr(r,t,e){let{frontmatter:s,body:n}=J(r),a=zs(n);return{filePath:t,agent:Xn(s.agent)??e,schema:fl(s.schema,Hs),lastUpdated:Xn(s.last_updated),lastReflection:Xn(s.last_reflection),tokenEstimate:us(Ke(a)),sections:a}}function zs(r){let t=new Map,e=(a,i)=>{let o=t.get(a)??[];o.push(i),t.set(a,o)},s="Observations";for(let a of r.split(`
|
|
11645
|
-
`)){let i=a.match(/^#{1,6}\s+(.+?)\s*$/);if(i){s=ml(i[1]??"");continue}let o=yl(a);o&&e(s,o)}let n=[];for(let a of dr){let i=t.get(a);i&&i.length&&n.push({name:a,entries:i})}return n}function yr(r){let t=Ke(r.sections),e={agent:r.agent,schema:r.schema||Hs,last_updated:r.lastUpdated??"",token_estimate:us(t)};return r.lastReflection&&(e.last_reflection=r.lastReflection),H(e,t||"## Observations")}function vr(r,t,e,s){if(t.length===0)return r;let n=r.sections.map(o=>({name:o.name,entries:[...o.entries]})),a=n.find(o=>o.name===e);return a||(a={name:e,entries:[]},n.push(a)),a.entries.push(...t),{...r,sections:n,lastUpdated:s??r.lastUpdated,tokenEstimate:us(Ke(n))}}var wl=["Recent","Observations","Procedures"];function wr(r,t){if(r.tokenEstimate<=t)return{wm:r,spilled:[]};let e=r.sections.map(o=>({name:o.name,entries:[...o.entries]})),s=[],n=Ke(e).length,a=()=>Math.ceil(n/4)>t;for(let o of wl){if(!a())break;let c=e.find(l=>l.name===o);if(c)for(;c.entries.length>0&&a();){let l=c.entries.findIndex(d=>!d.pinned);if(l===-1)break;let h=c.entries.splice(l,1)[0];h&&(s.push(h),n-=fr(h).length+1)}}let i=e.filter(o=>o.entries.length>0);return{wm:{...r,sections:i,tokenEstimate:us(Ke(i))},spilled:s}}function Zn(r,t,e,s){let n=zs(r);return{filePath:t,agent:e,schema:Hs,lastUpdated:s,tokenEstimate:us(Ke(n)),sections:n}}function br(r,t){let e=(r?.sections??[]).flatMap(i=>i.entries).filter(i=>i.pinned);if(e.length===0||t.some(i=>i.entries.some(o=>o.pinned)))return t;let n=t.map(i=>({name:i.name,entries:[...i.entries]})),a=n.find(i=>i.name==="Preferences");return a||(a={name:"Preferences",entries:[]},n.unshift(a)),a.entries.unshift(...e),n}var bl="When you learn a durable fact about the user, their preferences, or how to do your work better, save it to memory. Prefer the `remember` tool \u2014 call remember(fact, pin?, section?); it is the reliable way to record a memory. If that tool is not available, fall back to writing [REMEMBER] <one concise fact> [/REMEMBER] in your reply (use [REMEMBER:pin] for standing preferences and hard constraints). Record only durable, reusable facts \u2014 not transient task details. These notes persist into your future runs.";function Gs(r,t){if(!r.memory)return"";let s=(t?Ke(t.sections).trim():"")||"Nothing yet \u2014 this is a fresh agent.";return`## Memory
|
|
11646
|
-
${bl}
|
|
11647
|
-
|
|
11648
|
-
### What you've learned so far
|
|
11649
|
-
${s}`}var mt=require("child_process"),kr=require("fs"),Ys=require("os"),Et=require("path");function ea(){return(0,Ys.homedir)()}function xr(){if(process.platform==="darwin")return"/bin/zsh";for(let r of["/bin/bash","/bin/zsh","/bin/sh"])if((0,kr.existsSync)(r))return r;return"/bin/sh"}function kl(r){return`'${r.replace(/'/g,"'\\''")}'`}function dt(r,t,e){let s={cwd:e?.cwd,env:e?.env};if(process.platform==="win32")return(0,mt.spawn)(r,t,s);let n=xr(),a=[r,...t].map(kl).join(" ");return(0,mt.spawn)(n,["-l","-c",a],s)}function Sr(r,t){let e={cwd:t?.cwd,env:t?.env,stdio:["pipe","pipe","pipe"]};if(process.platform==="win32")return(0,mt.spawn)(r,[],{...e,shell:!0});let s=xr();return(0,mt.spawn)(s,["-l","-c",r],e)}function Cr(r){try{require("electron").shell.openExternal(r)}catch{switch(process.platform){case"darwin":(0,mt.spawn)("open",[r],{stdio:"ignore"});break;case"win32":(0,mt.spawn)("cmd.exe",["/c","start","",r.replace(/&/g,"^&")],{stdio:"ignore"});break;default:(0,mt.spawn)("xdg-open",[r],{stdio:"ignore"});break}}}function ye(r){return r.split(/\r?\n/)}function Tr(r){let t=(0,Ys.homedir)();if(process.platform==="win32")return[r,(0,Et.join)(process.env.APPDATA??"","Claude","claude.exe"),(0,Et.join)(process.env.LOCALAPPDATA??"","Claude","claude.exe"),(0,Et.join)(t,".local","bin","claude.exe"),"claude.exe","claude"].filter(s=>!!s&&Vs(s));let e=[r,(0,Et.join)(t,".local","bin","claude")];return process.platform==="darwin"&&e.push("/opt/homebrew/bin/claude"),e.push("/usr/local/bin/claude","/usr/bin/claude","claude"),e.filter(s=>!!s&&Vs(s))}function ta(r){let t=(0,Ys.homedir)();if(process.platform==="win32")return[r,(0,Et.join)(t,".local","bin","codex.exe"),"codex.exe","codex"].filter(s=>!!s&&Vs(s));let e=[r,(0,Et.join)(t,".local","bin","codex")];return process.platform==="darwin"&&e.push("/opt/homebrew/bin/codex"),e.push("/usr/local/bin/codex","/usr/bin/codex","codex"),e.filter(s=>!!s&&Vs(s))}function Vs(r){return!r||/[\n\r\0]/.test(r)?!1:r.startsWith("/")?/^[\w/.@+-]+$/.test(r):r.startsWith("~")?/^~[\w/.@+-]*$/.test(r):/^[a-zA-Z]:[\\/]/.test(r)?/^[a-zA-Z]:[\\/][\w\\/. @+-]+$/.test(r):r.startsWith("\\\\")?/^\\\\[\w\\/. @+-]+$/.test(r):!r.includes("/")&&!r.includes("\\")?/^[\w.@+-]+$/.test(r):!1}function sa(r){return!!(r.includes("/")||r.includes("\\"))}function _r(r){let t=new Map;for(let s of r){if(typeof s.costUsd!="number")continue;let n=t.get(s.agent);n?n.push(s):t.set(s.agent,[s])}let e=0;for(let s of t.values()){s.sort((a,i)=>a.ts.localeCompare(i.ts));let n=0;for(let a of s){let i=a.costUsd,o=i>=n?i-n:i;n=i,o!==i&&e++,a.costUsd=o}}return e}function Ht(r){return typeof r=="object"&&r!==null}function A(r){return typeof r=="string"?r:void 0}function Be(r,t){return typeof r=="boolean"?r:t}function Re(r,t){return typeof r=="number"&&Number.isFinite(r)?r:t}function ue(r){return Array.isArray(r)?r.filter(t=>typeof t=="string"):[]}function Ar(r){if(!Ht(r))return;let t={};for(let[e,s]of Object.entries(r))typeof s=="string"&&(t[e]=s);return Object.keys(t).length>0?t:void 0}var Er=!1;function Pr(r,t={}){let e=r.memory_token_budget??t.memory_token_budget;return e!==void 0?Re(e,js):((r.memory_max_entries??t.memory_max_entries)!==void 0&&!Er&&(Er=!0,console.info(`Agent Fleet: \`memory_max_entries\` is deprecated and no longer enforced; memory is now bounded by \`memory_token_budget\` (default ${js}). Set that field to tune memory size.`)),js)}function Rr(r,t={}){let e=s=>r[s]??t[s];return{enabled:Be(e("reflection_enabled"),!1),schedule:A(e("reflection_schedule"))??ir,recurrenceThreshold:Re(e("reflection_recurrence_threshold"),or),proposeSkills:Be(e("reflection_propose_skills"),!1),model:A(e("reflection_model"))}}function Dr(r){return(0,x.normalizePath)(r.replace(/\.md$/,".permissions.json"))}function Ir(r){let t=0;for(let e=0;e<r.length;e++){let s=r.charCodeAt(e);t=(t<<5)-t+s|0}return t.toString(36)}var ps=class{constructor(t,e){this.app=t;this.settings=e;this.vault=t.vault}agents=new Map;skills=new Map;tasks=new Map;channels=new Map;mcpServers=new Map;validationIssues=new Map;channelCredentialGetter;warnedFolderAgentModelConflict=new Set;warnedLegacyPerms=new Set;migratingMemory=new Set;vault;setChannelCredentialGetter(t){this.channelCredentialGetter=t}getVaultBasePath(){let t=this.vault.adapter;return t instanceof x.FileSystemAdapter?t.getBasePath():void 0}getFleetRoot(){return(0,x.normalizePath)(this.settings.fleetFolder)}getSubfolder(t){return(0,x.normalizePath)(`${this.getFleetRoot()}/${t}`)}async ensureFleetStructure(){let t=this.getFleetRoot(),e=!this.vault.getAbstractFileByPath(t);await this.ensureFolder(t);for(let s of rr)await this.ensureFolder(this.getSubfolder(s));return e}async ensureSamples(){let t=this.getFleetRoot();for(let e of Jn){let s=(0,x.normalizePath)(`${t}/${e.path}`),n=s.substring(0,s.lastIndexOf("/"));await this.ensureFolder(n),await this.createFileIfMissing(s,e.content)}}async updateDefaults(t){let e=this.getFleetRoot(),s={...t};for(let n of Jn){let a=(0,x.normalizePath)(`${e}/${n.path}`),i=Ir(n.content),o=t[n.path];if(o===i)continue;let c=this.vault.getAbstractFileByPath(a);if(!(c instanceof x.TFile)){let d=a.substring(0,a.lastIndexOf("/"));await this.ensureFolder(d),await this.createFileIfMissing(a,n.content),s[n.path]=i;continue}let l=await this.vault.cachedRead(c),h=Ir(l);(!o||h===o)&&(await this.vault.modify(c,n.content),s[n.path]=i)}return s}async loadAll(){this.agents.clear(),this.skills.clear(),this.tasks.clear(),this.channels.clear(),this.mcpServers.clear(),this.validationIssues.clear(),await this.loadFolderAgents(),await this.loadFolderSkills();let t=this.vault.getMarkdownFiles().filter(e=>e.path.startsWith(`${this.getFleetRoot()}/`));for(let e of t)await this.loadFile(e);return this.validateReferences(),this.getSnapshot()}async loadFile(t){let e=typeof t=="string"?this.vault.getAbstractFileByPath(t):t;if(!(e instanceof x.TFile)||e.extension!=="md")return;if(this.isInsideAgentFolder(e.path)){await this.reloadFolderAgentContaining(e.path);return}if(this.isInsideSkillFolder(e.path)){await this.reloadFolderSkillContaining(e.path);return}this.clearStoredFile(e.path);let s=`${this.getSubfolder("channels")}/`;if(e.path.startsWith(s)){if(!e.path.slice(s.length).includes("/")){let c=await this.vault.cachedRead(e),l=this.parseChannelFile(e.path,c);l&&this.channels.set(e.path,l)}return}let n=`${this.getSubfolder("mcp")}/`;if(e.path.startsWith(n)){if(!e.path.slice(n.length).includes("/")){let c=await this.vault.cachedRead(e),l=this.parseMcpServerFile(e.path,c);l&&this.mcpServers.set(e.path,l)}return}let a=await this.vault.cachedRead(e),i=this.parseFile(e.path,a);if(i)if("taskId"in i)this.tasks.set(e.path,i);else if("model"in i){if(!i.isFolder){let o=Dr(e.path),c=this.vault.getAbstractFileByPath(o);if(c instanceof x.TFile)try{let l=await this.vault.cachedRead(c),h=JSON.parse(l);i.permissionRules={allow:ue(h.allow),deny:ue(h.deny)}}catch{}}this.agents.set(e.path,i)}else this.skills.set(e.path,i)}async reloadFolderAgentContaining(t){let e=`${this.getSubfolder("agents")}/`,n=t.slice(e.length).split("/")[0];if(!n)return;let a=(0,x.normalizePath)(`${e}${n}`),i=(0,x.normalizePath)(`${a}/agent.md`);if(this.agents.delete(i),!(this.vault.getAbstractFileByPath(a)instanceof x.TFolder))return;let c=this.vault.getAbstractFileByPath(i);if(!(c instanceof x.TFile))return;let l=await this.loadFolderAgent(a,c);l&&this.agents.set(i,l)}isInsideAgentFolder(t){let e=`${this.getSubfolder("agents")}/`;return t.startsWith(e)?t.slice(e.length).includes("/"):!1}isInsideSkillFolder(t){let e=`${this.getSubfolder("skills")}/`;return t.startsWith(e)?t.slice(e.length).includes("/"):!1}async reloadFolderSkillContaining(t){let e=`${this.getSubfolder("skills")}/`,n=t.slice(e.length).split("/")[0];if(!n)return;let a=(0,x.normalizePath)(`${e}${n}`),i=(0,x.normalizePath)(`${a}/skill.md`);if(this.skills.delete(i),!(this.vault.getAbstractFileByPath(a)instanceof x.TFolder))return;let c=this.vault.getAbstractFileByPath(i);if(!(c instanceof x.TFile))return;let l=await this.loadFolderSkill(a,c);l&&this.skills.set(i,l)}async loadFolderSkills(){let t=this.vault.getAbstractFileByPath(this.getSubfolder("skills"));if(t instanceof x.TFolder)for(let e of t.children){if(!(e instanceof x.TFolder))continue;let s=(0,x.normalizePath)(`${e.path}/skill.md`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof x.TFile))continue;let a=await this.loadFolderSkill(e.path,n);a&&this.skills.set(s,a)}}async loadFolderSkill(t,e){let s=await this.vault.cachedRead(e),{frontmatter:n,body:a}=J(s),i=A(n.name);if(!i)return this.setIssue(e.path,"Folder skill skill.md requires string field `name`."),null;let o=async c=>{let l=(0,x.normalizePath)(`${t}/${c}`),h=this.vault.getAbstractFileByPath(l);if(!(h instanceof x.TFile))return"";let d=await this.vault.cachedRead(h);return J(d).body};return{filePath:e.path,name:i,description:A(n.description),tags:ue(n.tags),body:a,toolsBody:await o("tools.md"),referencesBody:await o("references.md"),examplesBody:await o("examples.md"),isFolder:!0}}async loadFolderAgents(){let t=this.vault.getAbstractFileByPath(this.getSubfolder("agents"));if(t instanceof x.TFolder)for(let e of t.children){if(!(e instanceof x.TFolder))continue;let s=(0,x.normalizePath)(`${e.path}/agent.md`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof x.TFile))continue;let a=await this.loadFolderAgent(e.path,n);a&&this.agents.set(s,a)}}async loadFolderAgent(t,e){let s=await this.vault.cachedRead(e),{frontmatter:n,body:a}=J(s),i=A(n.name);if(!i)return this.setIssue(e.path,"Folder agent agent.md requires string field `name`."),null;let o={},c=(0,x.normalizePath)(`${t}/config.md`),l=this.vault.getAbstractFileByPath(c);if(l instanceof x.TFile){let M=await this.vault.cachedRead(l);o=J(M).frontmatter}let h={allow:[],deny:[]},d=(0,x.normalizePath)(`${t}/permissions.json`),u=this.vault.getAbstractFileByPath(d);if(u instanceof x.TFile)try{let M=await this.vault.cachedRead(u),U=JSON.parse(M);h={allow:ue(U.allow),deny:ue(U.deny)}}catch{}if(h.allow.length===0&&h.deny.length===0){let M=ue(o.allowed_tools),U=ue(o.blocked_tools);(M.length>0||U.length>0)&&(h={allow:M,deny:U},this.warnedLegacyPerms.has(i)||(this.warnedLegacyPerms.add(i),console.warn(`Agent Fleet: "${i}" still uses legacy allowed_tools/blocked_tools in config.md. Permission rules now live in permissions.json. Open this agent in Edit and Save to migrate.`)))}let p="",m=(0,x.normalizePath)(`${t}/SKILLS.md`),f=this.vault.getAbstractFileByPath(m);if(f instanceof x.TFile){let M=await this.vault.cachedRead(f);p=J(M).body}let g="",y=(0,x.normalizePath)(`${t}/CONTEXT.md`),v=this.vault.getAbstractFileByPath(y);if(v instanceof x.TFile){let M=await this.vault.cachedRead(v);g=J(M).body}let k=!1,w="",S="",T=!0,_="",D="",O=(0,x.normalizePath)(`${t}/HEARTBEAT.md`),C=this.vault.getAbstractFileByPath(O);if(C instanceof x.TFile){let M=await this.vault.cachedRead(C),U=J(M);k=Be(U.frontmatter.enabled,!1),w=A(U.frontmatter.schedule)??"",T=Be(U.frontmatter.notify,!0),_=A(U.frontmatter.channel)??"",D=A(U.frontmatter.channel_target)??"",S=U.body}let E=A(n.model),P=A(o.model);E&&P&&E!==P&&(this.warnedFolderAgentModelConflict.has(i)||(this.warnedFolderAgentModelConflict.add(i),console.warn(`Agent Fleet: "${i}" has conflicting model fields \u2014 agent.md says "${E}", config.md says "${P}". config.md wins. Remove agent.md's model field or sync the values to silence this warning.`)));let N=P??E??this.settings.defaultModel;return{filePath:e.path,name:i,description:A(n.description),model:N,adapter:A(o.adapter)??"claude-code",permissionMode:A(o.permission_mode)??"bypassPermissions",effort:A(o.effort),maxRetries:Re(o.max_retries,1),skills:ue(n.skills),mcpServers:ue(n.mcp_servers),cwd:A(o.cwd)||A(n.cwd),enabled:Be(n.enabled,!0),timeout:Re(o.timeout,Re(n.timeout,300)),approvalRequired:ue(o.approval_required),memory:Be(o.memory,Be(n.memory,!1)),memoryMaxEntries:Re(o.memory_max_entries,100),memoryTokenBudget:Pr(o,n),reflection:Rr(o,n),autoCompactThreshold:Re(o.auto_compact_threshold??n.auto_compact_threshold,85),tags:ue(n.tags),avatar:A(n.avatar)??"",body:a,contextBody:g,skillsBody:p,env:this.parseEnvMap(o.env),permissionRules:h,isFolder:!0,heartbeatEnabled:k,heartbeatSchedule:w,heartbeatBody:S,heartbeatNotify:T,heartbeatChannel:_,heartbeatChannelTarget:D,wikiKeeper:this.parseWikiKeeperConfig(o.wiki_keeper??n.wiki_keeper),wikiReferences:this.parseWikiReferences(o.wiki_references??n.wiki_references)}}parseWikiReferences(t){if(!Array.isArray(t))return;let e=[];for(let s of t)if(typeof s=="string"&&s.trim())e.push({agent:s.trim()});else if(s&&typeof s=="object"){let n=s.agent;typeof n=="string"&&n.trim()&&e.push({agent:n.trim()})}return e.length>0?e:void 0}parseWikiKeeperConfig(t){if(!t||typeof t!="object")return;let e=t;return{scopeRoot:A(e.scope_root)??"",inboxPath:A(e.inbox_path)??"_sources/inbox",archivePath:A(e.archive_path)??"_sources/archive",failedPath:A(e.failed_path)??"_sources/failed",topicsRoot:A(e.topics_root)??"_topics",indexPath:A(e.index_path)??"index.md",logPath:A(e.log_path)??"log.md",watchedFolders:ue(e.watched_folders),excludePatterns:ue(e.exclude_patterns),watchedSince:A(e.watched_since)??"",fileSubstantiveAnswers:Be(e.file_substantive_answers,!0),obsidianUrlScheme:Be(e.obsidian_url_scheme,!0),maxTokensPerIngest:Re(e.max_tokens_per_ingest,6e4),maxTokensPerRefresh:Re(e.max_tokens_per_refresh,3e4),indexSplitThreshold:Re(e.index_split_threshold,100),dedupSimilarityThreshold:Re(e.dedup_similarity_threshold,.82),summaryStaleDays:Re(e.summary_stale_days,30),stateFile:A(e.state_file)??".wiki-keeper-state.json"}}removeFile(t){this.clearStoredFile(t)}getSnapshot(){return{agents:Array.from(this.agents.values()).sort((t,e)=>t.name.localeCompare(e.name)),skills:Array.from(this.skills.values()).sort((t,e)=>t.name.localeCompare(e.name)),tasks:Array.from(this.tasks.values()).sort((t,e)=>t.taskId.localeCompare(e.taskId)),channels:Array.from(this.channels.values()).sort((t,e)=>t.name.localeCompare(e.name)),mcpServers:Array.from(this.mcpServers.values()).sort((t,e)=>t.name.localeCompare(e.name)),validationIssues:Array.from(this.validationIssues.values()).flat()}}getAgentByName(t){return Array.from(this.agents.values()).find(e=>e.name===t)}getSkillByName(t){return Array.from(this.skills.values()).find(e=>e.name===t)}getTaskById(t){return Array.from(this.tasks.values()).find(e=>e.taskId===t)}getTasksForAgent(t){return Array.from(this.tasks.values()).filter(e=>e.agent===t)}getChannelByName(t){return Array.from(this.channels.values()).find(e=>e.name===t)}getChannelsForAgent(t){return Array.from(this.channels.values()).filter(e=>e.defaultAgent===t)}getMcpServers(){return Array.from(this.mcpServers.values()).sort((t,e)=>t.name.localeCompare(e.name))}getMcpServerByName(t){return Array.from(this.mcpServers.values()).find(e=>e.name===t)}getRunsRoot(){return this.getSubfolder("runs")}getMemoryPath(t){return(0,x.normalizePath)(`${this.getSubfolder("memory")}/${oe(t)}.md`)}getMemoryDir(t){return(0,x.normalizePath)(`${this.getSubfolder("memory")}/${oe(t)}`)}getWorkingMemoryPath(t){return(0,x.normalizePath)(`${this.getMemoryDir(t)}/working.md`)}getRawMemoryPath(t,e){let s=e.slice(0,10);return(0,x.normalizePath)(`${this.getMemoryDir(t)}/raw/${s}.md`)}async readWorkingMemory(t){let e=this.getWorkingMemoryPath(t),s=this.vault.getAbstractFileByPath(e);if(s instanceof x.TFile){let i=await this.vault.cachedRead(s);return gr(i,e,t)}let n=this.getMemoryPath(t),a=this.vault.getAbstractFileByPath(n);if(a instanceof x.TFile){let i=await this.vault.cachedRead(a),{body:o}=J(i);return Zn(o,e,t)}return null}async writeWorkingMemory(t,e){let s=this.getWorkingMemoryPath(t);await this.ensureFolder(this.getMemoryDir(t));let n=yr(e),a=this.vault.getAbstractFileByPath(s);a instanceof x.TFile?await this.vault.modify(a,n):await this.createFileIfMissing(s,n);let i=this.getMemoryPath(t);i!==s&&this.vault.getAbstractFileByPath(i)&&await this.trashFile(i)}async migrateLegacyMemory(t){let e=this.getWorkingMemoryPath(t);if(this.vault.getAbstractFileByPath(e))return;let s=this.getMemoryPath(t),n=this.vault.getAbstractFileByPath(s);if(n instanceof x.TFile&&!this.migratingMemory.has(t)){this.migratingMemory.add(t);try{let a=await this.vault.cachedRead(n),{body:i}=J(a),o=new Date().toISOString(),c=i.split(`
|
|
11650
|
-
`).map(d=>d.replace(/^\s*[-*]\s+/,"").trim()).filter(d=>d.length>0&&!/^#{1,6}\s/.test(d)),l=[`- ${o} [migrated] Imported ${c.length} legacy memory entr${c.length===1?"y":"ies"} (pre-v2).`,...c.map(d=>`- ${o} [migrated] ${d}`)];await this.appendRawMemory(t,l,o);let h=Zn(i,e,t,o);await this.writeWorkingMemory(t,h)}finally{this.migratingMemory.delete(t)}}}async migrateAllLegacyMemory(){for(let t of this.getSnapshot().agents)if(t.memory)try{await this.migrateLegacyMemory(t.name)}catch(e){console.warn(`Agent Fleet: legacy memory migration failed for "${t.name}"`,e)}}getPendingDir(t){return(0,x.normalizePath)(`${this.getMemoryDir(t)}/pending`)}getPendingDirAbsolutePath(t){let e=this.vault.adapter;return e instanceof x.FileSystemAdapter?(0,Mr.join)(e.getBasePath(),this.getPendingDir(t)):null}async ensureMemoryDir(t){await this.ensureFolder(this.getMemoryDir(t))}async readAndClearPending(t){let e=this.vault.adapter,s=this.getPendingDir(t),n;try{if(!await e.exists(s))return[];n=(await e.list(s)).files}catch{return[]}let a=[];for(let i of n)if(i.endsWith(".json"))try{let o=await e.read(i);await e.remove(i);for(let c of o.split(`
|
|
11651
|
-
`))c.trim().length>0&&a.push(c)}catch{}return a}async readRecentRaw(t,e=2){let s=(0,x.normalizePath)(`${this.getMemoryDir(t)}/raw`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof x.TFolder))return"";let a=n.children.filter(o=>o instanceof x.TFile&&o.extension==="md").sort((o,c)=>c.name.localeCompare(o.name)).slice(0,e),i=[];for(let o of a.reverse())i.push(`### ${o.basename}
|
|
11652
|
-
${await this.vault.cachedRead(o)}`);return i.join(`
|
|
11653
|
-
|
|
11654
|
-
`)}getCandidatesPath(t){return(0,x.normalizePath)(`${this.getMemoryDir(t)}/candidates.json`)}async readCandidates(t){let e=this.getCandidatesPath(t),s=this.vault.getAbstractFileByPath(e);if(!(s instanceof x.TFile))return[];try{let n=JSON.parse(await this.vault.cachedRead(s));return Array.isArray(n)?n:[]}catch{return[]}}async writeCandidates(t,e){let s=this.getCandidatesPath(t);await this.ensureFolder(this.getMemoryDir(t));let n=JSON.stringify(e,null,2),a=this.vault.getAbstractFileByPath(s);a instanceof x.TFile?await this.vault.modify(a,n):await this.createFileIfMissing(s,n)}getProposalsDir(){return(0,x.normalizePath)(`${this.getFleetRoot()}/proposals`)}async listProposals(){let t=this.vault.getAbstractFileByPath(this.getProposalsDir());if(!(t instanceof x.TFolder))return[];let e=[];for(let s of t.children){if(!(s instanceof x.TFile)||s.extension!=="md")continue;let n=await this.readProposal(s.basename);n&&e.push(n)}return e.sort((s,n)=>n.created.localeCompare(s.created)),e}async readProposal(t){let e=(0,x.normalizePath)(`${this.getProposalsDir()}/${t}.md`),s=this.vault.getAbstractFileByPath(e);if(!(s instanceof x.TFile))return null;let{frontmatter:n,body:a}=J(await this.vault.cachedRead(s)),i=n.type==="skill_modify"?"skill_modify":"skill_create",o=n.status==="accepted"||n.status==="rejected"?n.status:"pending";return{id:t,type:i,agent:A(n.agent)??"",status:o,created:A(n.created)??"",targetSkill:A(n.target_skill),candidate:A(n.candidate),evidence:ue(n.evidence),rationale:A(n.rationale)??"",body:a}}async writeProposal(t){await this.ensureFolder(this.getProposalsDir());let e=(0,x.normalizePath)(`${this.getProposalsDir()}/${t.id}.md`),s={id:t.id,type:t.type,agent:t.agent,status:t.status,created:t.created,target_skill:t.targetSkill||void 0,candidate:t.candidate||void 0,evidence:t.evidence.length?t.evidence:void 0,rationale:t.rationale||void 0},n=H(s,t.body||""),a=this.vault.getAbstractFileByPath(e);a instanceof x.TFile?await this.vault.modify(a,n):await this.createFileIfMissing(e,n)}async setProposalStatus(t,e){let s=await this.readProposal(t);s&&(s.status=e,await this.writeProposal(s))}async applyProposal(t){if(t.type==="skill_create"){let e=t.targetSkill||`learned-${oe(t.rationale).slice(0,24)||"skill"}`,s=await this.getAvailablePath(this.getSubfolder("skills"),oe(e)),a={name:s.split("/").pop()?.replace(/\.md$/,"")||oe(e),description:t.rationale||`Auto-proposed from recurring pattern for ${t.agent}.`,tags:["proposed"]};return await this.vault.create(s,H(a,t.body||"Skill instructions go here.")),s}if(t.targetSkill){let e=this.getSkillByName(t.targetSkill);if(e){let s=this.vault.getAbstractFileByPath(e.filePath);if(s instanceof x.TFile){let n=await this.vault.cachedRead(s),a=`
|
|
11655
|
-
|
|
11656
|
-
## Proposed update (${new Date().toISOString().slice(0,10)})
|
|
11657
|
-
${t.body}`;return await this.vault.modify(s,`${n.trimEnd()}${a}
|
|
11658
|
-
`),e.filePath}}}return null}async deleteProposal(t){await this.trashFile((0,x.normalizePath)(`${this.getProposalsDir()}/${t}.md`))}async appendRawMemory(t,e,s){if(e.length===0)return;let n=this.getRawMemoryPath(t,s);await this.ensureFolder(n.replace(/\/[^/]+$/,""));let a=e.map(o=>o.trimEnd()).join(`
|
|
11659
|
-
`),i=this.vault.getAbstractFileByPath(n);if(i instanceof x.TFile){let o=await this.vault.cachedRead(i);await this.vault.modify(i,`${o.trimEnd()}
|
|
11660
|
-
${a}
|
|
11661
|
-
`)}else await this.createFileIfMissing(n,`${a}
|
|
11662
|
-
`)}getConversationsDir(t){if(t.isFolder){let s=t.filePath.replace(/\/agent\.md$/,"");return(0,x.normalizePath)(`${s}/conversations`)}let e=this.getMemoryPath(t.name).replace(/\/[^/]+$/,"");return(0,x.normalizePath)(`${e}/${t.name}-conversations`)}getConversationPath(t,e){let s=this.getConversationsDir(t),n=oe(e)||"conversation";return(0,x.normalizePath)(`${s}/${n}.json`)}async listConversations(t){let e=[],s=this.getConversationsDir(t),n=this.vault.getAbstractFileByPath(s);if(n instanceof x.TFolder)for(let a of n.children){if(!(a instanceof x.TFile)||a.extension!=="json")continue;let i=a.basename,o=await this.readConversationMeta(a,i);o&&e.push(o)}return e.sort((a,i)=>i.lastActive.localeCompare(a.lastActive)),e}async readConversationMeta(t,e){try{let s=await this.vault.cachedRead(t),n=JSON.parse(s);return{id:e,name:n.name?.trim()||"Untitled",lastActive:n.lastActive??new Date(t.stat.mtime).toISOString(),messageCount:Array.isArray(n.messages)?n.messages.length:0}}catch{return null}}async createConversation(t,e,s){let n=this.getConversationPath(t,e);if(this.vault.getAbstractFileByPath(n)instanceof x.TFile)return;let i=n.replace(/\/[^/]+$/,"");await this.ensureFolder(i);let o=new Date().toISOString(),c={sessionId:null,messages:[],lastActive:o,createdAt:o,name:s.trim()};await this.vault.create(n,JSON.stringify(c,null,2))}async renameConversation(t,e,s){let n=this.getConversationPath(t,e),a=this.vault.getAbstractFileByPath(n);if(!(a instanceof x.TFile))return;let i=await this.vault.cachedRead(a),o;try{o=JSON.parse(i)}catch{return}o.name=s.trim(),await this.vault.modify(a,JSON.stringify(o,null,2))}async deleteConversation(t,e){let s=this.getConversationPath(t,e),n=this.vault.getAbstractFileByPath(s);n instanceof x.TFile&&await this.app.fileManager.trashFile(n);let a=s.replace(/\.json$/,".threads"),i=this.vault.getAbstractFileByPath(a);i instanceof x.TFolder&&await this.app.fileManager.trashFile(i);let o=this.getConversationsDir(t),c=this.vault.getAbstractFileByPath(o);c instanceof x.TFolder&&c.children.length===0&&await this.app.fileManager.trashFile(c)}async getMemory(t){let e=await this.readWorkingMemory(t);return e?{filePath:e.filePath,agent:e.agent,lastUpdated:e.lastUpdated,body:Ke(e.sections)}:null}async appendMemory(t,e){if(e.length===0)return;let s=this.getMemoryPath(t),n=this.vault.getAbstractFileByPath(s),a=new Date().toISOString(),i=e.map(o=>`- ${o.trim()}`).join(`
|
|
11663
|
-
`);if(n instanceof x.TFile){let c=`${(await this.getMemory(t))?.body.trim()||"## Learned Context"}
|
|
11664
|
-
|
|
11665
|
-
${i}`.trim();await this.vault.modify(n,H({agent:t,last_updated:a},c));return}await this.createFileIfMissing(s,H({agent:t,last_updated:a},`## Learned Context
|
|
11666
|
-
|
|
11667
|
-
${i}`))}async listRecentRuns(t=50){let e=this.vault.getAbstractFileByPath(this.getRunsRoot());if(!(e instanceof x.TFolder))return[];let s=[];this.collectMarkdownChildren(e,s),s.sort((i,o)=>o.path.localeCompare(i.path));let n=s.slice(0,t),a=[];for(let i of n){let o=await this.readRunLog(i);o&&a.push(o)}return a.sort((i,o)=>o.started.localeCompare(i.started))}async listRunsSince(t){let e=this.vault.getAbstractFileByPath(this.getRunsRoot());if(!(e instanceof x.TFolder))return[];let s=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,n=[];for(let i of e.children)i instanceof x.TFolder&&(i.name<s||this.collectMarkdownChildren(i,n));let a=[];for(let i of n){let o=await this.readRunLog(i);o&&a.push(o)}return a.sort((i,o)=>o.started.localeCompare(i.started))}usageLedgerPath(t){return(0,x.normalizePath)(`${this.getSubfolder("usage")}/${t.slice(0,10)}.jsonl`)}async appendUsage(t){await this.ensureFolder(this.getSubfolder("usage"));let e=this.usageLedgerPath(t.ts),s=`${JSON.stringify(t)}
|
|
11668
|
-
`,n=this.vault.adapter;await n.exists(e)?await n.append(e,s):await n.write(e,s)}async readUsageSince(t){let e=this.getSubfolder("usage"),s=this.vault.adapter;if(!await s.exists(e))return[];let n=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,a=[],i=await s.list(e);for(let o of i.files){if(!o.endsWith(".jsonl")||(o.split("/").pop()??"").replace(/\.jsonl$/,"")<n)continue;let l;try{l=await s.read(o)}catch{continue}for(let h of l.split(`
|
|
11669
|
-
`)){let d=h.trim();if(d)try{a.push(JSON.parse(d))}catch{}}}return a}async migrateUsageLedgerCosts(){let t=this.getSubfolder("usage"),e=this.vault.adapter;if(!await e.exists(t))return null;let s=(0,x.normalizePath)(`${t}/.cost-delta-v1`);if(await e.exists(s))return null;try{let n=await e.list(t),a=[],i=[];for(let c of n.files){if(!c.endsWith(".jsonl"))continue;let l;try{l=await e.read(c)}catch{continue}let h=[];for(let d of l.split(`
|
|
11670
|
-
`)){let u=d.trim();if(u)try{h.push(JSON.parse(u))}catch{}}a.push({path:c,records:h}),i.push(...h)}let o=_r(i);if(o>0)for(let{path:c,records:l}of a){if(l.length===0)continue;let h=l.map(d=>JSON.stringify(d)).join(`
|
|
11671
|
-
`)+`
|
|
11672
|
-
`;await e.write(c,h)}return await e.write(s,`migrated ${i.length} rows; corrected ${o}
|
|
11673
|
-
`),{files:a.length,rows:i.length,changed:o}}catch(n){return console.error("Agent Fleet: usage-ledger cost migration failed (ledger left untouched)",n),null}}async readRunLog(t){let e=await this.vault.cachedRead(t),{frontmatter:s,body:n}=J(e),a=n.match(/## Prompt\n([\s\S]*?)(?:\n## Result\n|\n## Output\n|$)/),i=n.match(/## Result\n([\s\S]*?)(?:\n## Output\n|$)/),o=n.match(/## Output\n([\s\S]*?)(?:\n## Tools Used\n|$)/),c=n.match(/## Tools Used\n([\s\S]*?)(?:\n## STDERR\n|$)/);return{filePath:t.path,runId:A(s.run_id)??t.basename,agent:A(s.agent)??"unknown",task:A(s.task)??"unknown",status:A(s.status)??"failure",started:A(s.started)??new Date(t.stat.ctime).toISOString(),completed:A(s.completed),durationSeconds:Re(s.duration_seconds,0),tokensUsed:typeof s.tokens_used=="number"?s.tokens_used:void 0,costUsd:typeof s.cost_usd=="number"?s.cost_usd:void 0,model:A(s.model)??it.defaultModel,modelSource:(()=>{let l=A(s.model_source);if(l==="task"||l==="agent"||l==="settings"||l==="cli-default")return l})(),concreteModel:A(s.resolved_concrete_model),exitCode:typeof s.exit_code=="number"?s.exit_code:null,tags:ue(s.tags),prompt:a?.[1]?.trim()??"",output:o?.[1]?.trim()??"",finalResult:i?.[1]?.trim()||void 0,toolsUsed:c?.[1]?ye(c[1]).map(l=>l.replace(/^- /,"").trim()).filter(Boolean):[],approvals:this.parseApprovals(s.approvals)}}async writeRunLog(t){let e=new Date(t.started),s=(0,x.normalizePath)(`${this.getRunsRoot()}/${e.toISOString().slice(0,10)}`);await this.ensureFolder(s);let n=`${e.toISOString().slice(11,19).replace(/:/g,"")}-${oe(t.agent)}-${oe(t.task)}.md`,a=(0,x.normalizePath)(`${s}/${n}`),i=H({run_id:t.runId,agent:t.agent,task:t.task,status:t.status,started:t.started,completed:t.completed,duration_seconds:t.durationSeconds,tokens_used:t.tokensUsed,cost_usd:t.costUsd,model:t.model,model_source:t.modelSource,resolved_concrete_model:t.concreteModel,exit_code:t.exitCode,tags:t.tags,approvals:t.approvals},["## Prompt","",t.prompt.trim(),"",...t.finalResult&&t.finalResult.trim()?["## Result","",t.finalResult.trim(),""]:[],"## Output","",t.output.trim()||"(no output)","","## Tools Used","",...t.toolsUsed.length>0?t.toolsUsed.map(c=>`- ${c}`):["- none"],...t.stderr?["","## STDERR","",t.stderr.trim()]:[]].join(`
|
|
11674
|
-
`)),o=this.vault.getAbstractFileByPath(a);return o instanceof x.TFile?await this.vault.modify(o,i):await this.vault.create(a,i),a}async updateTaskRunMetadata(t,e){let s=this.vault.getAbstractFileByPath(t.filePath);if(!(s instanceof x.TFile))return;let n=await this.vault.cachedRead(s),{frontmatter:a,body:i}=J(n),o={...a,last_run:e.lastRun??t.lastRun,next_run:e.nextRun??t.nextRun,run_count:e.runCount??t.runCount};await this.vault.modify(s,H(o,i)),await this.loadFile(s)}async setApprovalDecision(t,e,s){let n=this.vault.getAbstractFileByPath(t);if(!(n instanceof x.TFile))return;let a=await this.vault.cachedRead(n),{frontmatter:i,body:o}=J(a),c=(this.parseApprovals(i.approvals)??[]).map(l=>l.tool===e?{...l,status:s,resolvedAt:new Date().toISOString()}:l);await this.vault.modify(n,H({...i,approvals:c},o))}async createAgentTemplate(t){let e=await this.getAvailablePath(this.getSubfolder("agents"),oe(t)),s=`---
|
|
11675
|
-
name: ${oe(t)}
|
|
11638
|
+
`}function z(a){return a.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")}function At(a,e){return a.length<=e?a:`${a.slice(0,e-1)}\u2026`}var xn=class{constructor(e,t){this.app=e;this.getLegacyMemoryPath=t;this.vault=e.vault}vault;getConversationsDir(e){if(e.isFolder){let s=e.filePath.replace(/\/agent\.md$/,"");return(0,nt.normalizePath)(`${s}/conversations`)}let t=this.getLegacyMemoryPath(e.name).replace(/\/[^/]+$/,"");return(0,nt.normalizePath)(`${t}/${e.name}-conversations`)}getConversationPath(e,t){let s=this.getConversationsDir(e),n=z(t)||"conversation";return(0,nt.normalizePath)(`${s}/${n}.json`)}async listConversations(e){let t=[],s=this.getConversationsDir(e),n=this.vault.getAbstractFileByPath(s);if(n instanceof nt.TFolder)for(let r of n.children){if(!(r instanceof nt.TFile)||r.extension!=="json")continue;let i=r.basename,o=await this.readConversationMeta(r,i);o&&t.push(o)}return t.sort((r,i)=>i.lastActive.localeCompare(r.lastActive)),t}async readConversationMeta(e,t){try{let s=await this.vault.cachedRead(e),n=JSON.parse(s);return{id:t,name:n.name?.trim()||"Untitled",lastActive:n.lastActive??new Date(e.stat.mtime).toISOString(),messageCount:Array.isArray(n.messages)?n.messages.length:0}}catch(s){return console.warn(`Agent Fleet: skipping unreadable conversation file ${e.path}`,s),null}}async createConversation(e,t,s){let n=this.getConversationPath(e,t);if(this.vault.getAbstractFileByPath(n)instanceof nt.TFile)return;let i=n.replace(/\/[^/]+$/,"");await fe(this.vault,i);let o=new Date().toISOString(),l={sessionId:null,messages:[],lastActive:o,createdAt:o,name:s.trim()};await this.vault.create(n,JSON.stringify(l,null,2))}async renameConversation(e,t,s){let n=this.getConversationPath(e,t),r=this.vault.getAbstractFileByPath(n);if(!(r instanceof nt.TFile))return;let i=await this.vault.cachedRead(r),o;try{o=JSON.parse(i)}catch(l){console.warn(`Agent Fleet: cannot rename conversation \u2014 invalid JSON in ${n}`,l);return}o.name=s.trim(),await this.vault.modify(r,JSON.stringify(o,null,2))}async deleteConversation(e,t){let s=this.getConversationPath(e,t),n=this.vault.getAbstractFileByPath(s);n instanceof nt.TFile&&await this.app.fileManager.trashFile(n);let r=s.replace(/\.json$/,".threads"),i=this.vault.getAbstractFileByPath(r);i instanceof nt.TFolder&&await this.app.fileManager.trashFile(i);let o=this.getConversationsDir(e),l=this.vault.getAbstractFileByPath(o);l instanceof nt.TFolder&&l.children.length===0&&await this.app.fileManager.trashFile(l)}};var N=require("obsidian");var ze=require("obsidian");var ei=!1;function ti(a,e={}){let t=a.memory_token_budget??e.memory_token_budget;return t!==void 0?Pe(t,bn):((a.memory_max_entries??e.memory_max_entries)!==void 0&&!ei&&(ei=!0,console.info(`Agent Fleet: \`memory_max_entries\` is deprecated and no longer enforced; memory is now bounded by \`memory_token_budget\` (default ${bn}). Set that field to tune memory size.`)),bn)}function si(a,e={}){let t=s=>a[s]??e[s];return{enabled:Ie(t("reflection_enabled"),!1),schedule:C(t("reflection_schedule"))??Qr,recurrenceThreshold:Pe(t("reflection_recurrence_threshold"),Zr),proposeSkills:Ie(t("reflection_propose_skills"),!1),model:C(t("reflection_model"))}}function Os(a){return(0,ze.normalizePath)(a.replace(/\.md$/,".permissions.json"))}function ni(a){if(!Tt(a))return{};let e={};for(let[t,s]of Object.entries(a))typeof s=="string"?e[t]=s:(typeof s=="number"||typeof s=="boolean")&&(e[t]=String(s));return e}function Wc(a){if(!Array.isArray(a))return;let e=[];for(let t of a)if(typeof t=="string"&&t.trim())e.push({agent:t.trim()});else if(t&&typeof t=="object"){let s=t.agent;typeof s=="string"&&s.trim()&&e.push({agent:s.trim()})}return e.length>0?e:void 0}function qc(a){if(!a||typeof a!="object")return;let e=a;return{scopeRoot:C(e.scope_root)??"",inboxPath:C(e.inbox_path)??"_sources/inbox",archivePath:C(e.archive_path)??"_sources/archive",failedPath:C(e.failed_path)??"_sources/failed",topicsRoot:C(e.topics_root)??"_topics",indexPath:C(e.index_path)??"index.md",logPath:C(e.log_path)??"log.md",watchedFolders:Q(e.watched_folders),excludePatterns:Q(e.exclude_patterns),watchedSince:C(e.watched_since)??"",fileSubstantiveAnswers:Ie(e.file_substantive_answers,!0),obsidianUrlScheme:Ie(e.obsidian_url_scheme,!0),maxTokensPerIngest:Pe(e.max_tokens_per_ingest,6e4),maxTokensPerRefresh:Pe(e.max_tokens_per_refresh,3e4),indexSplitThreshold:Pe(e.index_split_threshold,100),dedupSimilarityThreshold:Pe(e.dedup_similarity_threshold,.82),summaryStaleDays:Pe(e.summary_stale_days,30),stateFile:C(e.state_file)??".wiki-keeper-state.json"}}function ai(a,e,t){let{frontmatter:s,body:n}=W(t);if(!Tt(s))return a.reportIssue(e,"Invalid frontmatter."),null;let r=C(s.name),i=C(s.model)??a.settings.defaultModel;if(!r||!i)return a.reportIssue(e,"Agent requires string field `name` and a valid model or default model setting."),null;let o=Q(s.allowed_tools),l=Q(s.blocked_tools);return(o.length>0||l.length>0)&&!a.warnedLegacyPerms.has(r)&&(a.warnedLegacyPerms.add(r),console.warn(`Agent Fleet: "${r}" still uses legacy allowed_tools/blocked_tools in its frontmatter. Permission rules now live in <name>.permissions.json beside the .md. Open Edit and Save to migrate.`)),{filePath:e,name:r,description:C(s.description),model:i,adapter:C(s.adapter)??"claude-code",permissionMode:C(s.permission_mode)??"bypassPermissions",effort:C(s.effort),maxRetries:Pe(s.max_retries,1),skills:Q(s.skills),mcpServers:Q(s.mcp_servers),cwd:C(s.cwd),enabled:Ie(s.enabled,!0),timeout:Pe(s.timeout,300),approvalRequired:Q(s.approval_required),memory:Ie(s.memory,!1),memoryMaxEntries:Pe(s.memory_max_entries,100),memoryTokenBudget:ti(s),reflection:si(s),autoCompactThreshold:Pe(s.auto_compact_threshold,85),tags:Q(s.tags),avatar:C(s.avatar)??"",body:n,contextBody:"",skillsBody:"",env:ni(s.env),permissionRules:{allow:o,deny:l},isFolder:!1,heartbeatEnabled:!1,heartbeatSchedule:"",heartbeatBody:"",heartbeatNotify:!0,heartbeatChannel:"",heartbeatChannelTarget:""}}function ri(a,e,t){let{frontmatter:s,body:n}=W(t),r=C(s.name);return r?{filePath:e,name:r,description:C(s.description),tags:Q(s.tags),body:n,toolsBody:"",referencesBody:"",examplesBody:"",isFolder:!1}:(a.reportIssue(e,"Skill requires string field `name`."),null)}function ii(a,e,t){let{frontmatter:s,body:n}=W(t),r=C(s.task_id),i=C(s.agent),o=C(s.type);if(!r||!i||!o)return a.reportIssue(e,"Task requires `task_id`, `agent`, and `type`."),null;if(o==="recurring"&&!C(s.schedule))return a.reportIssue(e,"Recurring task requires `schedule`."),null;if(o==="once"&&!C(s.run_at))return a.reportIssue(e,"One-time task requires `run_at`."),null;let l=C(s.priority),d=l&&["low","medium","high","critical"].includes(l)?l:"medium";return{filePath:e,taskId:r,agent:i,schedule:C(s.schedule),runAt:C(s.run_at),type:o,priority:d,enabled:Ie(s.enabled,!0),created:C(s.created)??new Date().toISOString(),lastRun:C(s.last_run),nextRun:C(s.next_run),runCount:Pe(s.run_count,0),catchUp:Ie(s.catch_up,a.settings.catchUpMissedTasks),effort:C(s.effort),model:C(s.model),channel:C(s.channel),channelTarget:C(s.channel_target),tags:Q(s.tags),body:n}}function oi(a,e,t){let{frontmatter:s,body:n}=W(t),r=C(s.name);if(!r)return a.reportIssue(e,"Channel requires string field `name`."),null;let i=C(s.type),o=["slack","telegram","discord"];if(!i||!o.includes(i))return a.reportIssue(e,`Channel \`${r}\` requires \`type\` to be one of: ${o.join(", ")}.`),null;let l=i,c=C(s.default_agent)??C(s.agent);if(!c)return a.reportIssue(e,`Channel \`${r}\` requires \`default_agent\` (or \`agent\`).`),null;let d=Q(s.allowed_agents),u=C(s.credential_ref);if(!u)return a.reportIssue(e,`Channel \`${r}\` requires \`credential_ref\` pointing at a configured credential.`),null;let h=Tt(s.transport)?s.transport:{};return{filePath:e,name:r,type:l,defaultAgent:c,allowedAgents:d,enabled:Ie(s.enabled,!0),credentialRef:u,allowedUsers:Q(s.allowed_users),perUserSessions:Ie(s.per_user_sessions,!0),channelContext:C(s.channel_context)??"",transport:h,tags:Q(s.tags),body:n}}async function Ba(a,e,t){let s=await a.vault.cachedRead(t),{frontmatter:n,body:r}=W(s),i=C(n.name);if(!i)return a.reportIssue(t.path,"Folder skill skill.md requires string field `name`."),null;let o=async l=>{let c=(0,ze.normalizePath)(`${e}/${l}`),d=a.vault.getAbstractFileByPath(c);if(!(d instanceof ze.TFile))return"";let u=await a.vault.cachedRead(d);return W(u).body};return{filePath:t.path,name:i,description:C(n.description),tags:Q(n.tags),body:r,toolsBody:await o("tools.md"),referencesBody:await o("references.md"),examplesBody:await o("examples.md"),isFolder:!0}}async function Ua(a,e,t){let s=await a.vault.cachedRead(t),{frontmatter:n,body:r}=W(s),i=C(n.name);if(!i)return a.reportIssue(t.path,"Folder agent agent.md requires string field `name`."),null;let o={},l=(0,ze.normalizePath)(`${e}/config.md`),c=a.vault.getAbstractFileByPath(l);if(c instanceof ze.TFile){let F=await a.vault.cachedRead(c);o=W(F).frontmatter}let d={allow:[],deny:[]},u=(0,ze.normalizePath)(`${e}/permissions.json`);a.clearIssue(u);let h=a.vault.getAbstractFileByPath(u);if(h instanceof ze.TFile)try{let F=await a.vault.cachedRead(h),B=JSON.parse(F);d={allow:Q(B.allow),deny:Q(B.deny)}}catch(F){console.error(`Agent Fleet: invalid JSON in ${u} \u2014 agent "${i}" is running with EMPTY permission rules`,F),a.reportIssue(u,`Invalid JSON in permissions.json for agent \`${i}\` \u2014 permission rules are NOT applied. Fix or delete the file.`)}if(d.allow.length===0&&d.deny.length===0){let F=Q(o.allowed_tools),B=Q(o.blocked_tools);(F.length>0||B.length>0)&&(d={allow:F,deny:B},a.warnedLegacyPerms.has(i)||(a.warnedLegacyPerms.add(i),console.warn(`Agent Fleet: "${i}" still uses legacy allowed_tools/blocked_tools in config.md. Permission rules now live in permissions.json. Open this agent in Edit and Save to migrate.`)))}let p="",m=(0,ze.normalizePath)(`${e}/SKILLS.md`),f=a.vault.getAbstractFileByPath(m);if(f instanceof ze.TFile){let F=await a.vault.cachedRead(f);p=W(F).body}let g="",w=(0,ze.normalizePath)(`${e}/CONTEXT.md`),y=a.vault.getAbstractFileByPath(w);if(y instanceof ze.TFile){let F=await a.vault.cachedRead(y);g=W(F).body}let v=!1,k="",b="",P=!0,A="",M="",E=(0,ze.normalizePath)(`${e}/HEARTBEAT.md`),x=a.vault.getAbstractFileByPath(E);if(x instanceof ze.TFile){let F=await a.vault.cachedRead(x),B=W(F);v=Ie(B.frontmatter.enabled,!1),k=C(B.frontmatter.schedule)??"",P=Ie(B.frontmatter.notify,!0),A=C(B.frontmatter.channel)??"",M=C(B.frontmatter.channel_target)??"",b=B.body}let _=C(n.model),R=C(o.model);_&&R&&_!==R&&(a.warnedFolderAgentModelConflict.has(i)||(a.warnedFolderAgentModelConflict.add(i),console.warn(`Agent Fleet: "${i}" has conflicting model fields \u2014 agent.md says "${_}", config.md says "${R}". config.md wins. Remove agent.md's model field or sync the values to silence this warning.`)));let O=R??_??a.settings.defaultModel;return{filePath:t.path,name:i,description:C(n.description),model:O,adapter:C(o.adapter)??"claude-code",permissionMode:C(o.permission_mode)??"bypassPermissions",effort:C(o.effort),maxRetries:Pe(o.max_retries,1),skills:Q(n.skills),mcpServers:Q(n.mcp_servers),cwd:C(o.cwd)||C(n.cwd),enabled:Ie(n.enabled,!0),timeout:Pe(o.timeout,Pe(n.timeout,300)),approvalRequired:Q(o.approval_required),memory:Ie(o.memory,Ie(n.memory,!1)),memoryMaxEntries:Pe(o.memory_max_entries,100),memoryTokenBudget:ti(o,n),reflection:si(o,n),autoCompactThreshold:Pe(o.auto_compact_threshold??n.auto_compact_threshold,85),tags:Q(n.tags),avatar:C(n.avatar)??"",body:r,contextBody:g,skillsBody:p,env:ni(o.env),permissionRules:d,isFolder:!0,heartbeatEnabled:v,heartbeatSchedule:k,heartbeatBody:b,heartbeatNotify:P,heartbeatChannel:A,heartbeatChannelTarget:M,wikiKeeper:qc(o.wiki_keeper??n.wiki_keeper),wikiReferences:Wc(o.wiki_references??n.wiki_references)}}var Sn=class{constructor(e,t){this.app=e;this.deps=t;this.vault=e.vault}vault;get store(){return this.deps.store}async updateTaskRunMetadata(e,t){let s=this.vault.getAbstractFileByPath(e.filePath);if(!(s instanceof N.TFile))return;let n=await this.vault.cachedRead(s),{frontmatter:r,body:i}=W(n),o={...r,last_run:t.lastRun??e.lastRun,next_run:t.nextRun??e.nextRun,run_count:t.runCount??e.runCount};await this.vault.modify(s,U(o,i)),await this.store.loadFile(s)}async createAgentTemplate(e){let t=await _t(this.vault,this.deps.getSubfolder("agents"),z(e)),s=`---
|
|
11639
|
+
name: ${z(e)}
|
|
11676
11640
|
description:
|
|
11677
11641
|
enabled: true
|
|
11678
11642
|
skills: []
|
|
@@ -11680,37 +11644,74 @@ tags: []
|
|
|
11680
11644
|
---
|
|
11681
11645
|
|
|
11682
11646
|
Agent instructions go here.
|
|
11683
|
-
|
|
11684
|
-
`)}return
|
|
11685
|
-
name: ${
|
|
11647
|
+
`,n=await this.vault.create(t,s);return await this.store.loadFile(n),n}async createAgentFolder(e){let t=z(e.name),s=(0,N.normalizePath)(`${this.deps.getSubfolder("agents")}/${t}`);await fe(this.vault,s);let n={name:e.name,description:e.description||void 0,avatar:e.avatar||void 0,enabled:e.enabled??!0,tags:e.tags,skills:e.skills,mcp_servers:e.mcpServers?.length?e.mcpServers:void 0};e.model&&e.model!=="default"&&(n.model=e.model);let r=(0,N.normalizePath)(`${s}/agent.md`);await this.vault.create(r,U(n,e.systemPrompt||""));let i={model:e.model||"default",adapter:e.adapter||"claude-code",timeout:e.timeout,max_retries:1,cwd:e.cwd||"",permission_mode:e.permissionMode||"bypassPermissions",effort:e.effort||void 0,approval_required:e.approvalRequired,memory:e.memory,memory_max_entries:e.memoryMaxEntries};typeof e.autoCompactThreshold=="number"&&(i.auto_compact_threshold=e.autoCompactThreshold),e.wikiReferences&&e.wikiReferences.length>0&&(i.wiki_references=e.wikiReferences.map(u=>({agent:u})));let o=(0,N.normalizePath)(`${s}/config.md`);await this.vault.create(o,U(i,""));let l=(0,N.normalizePath)(`${s}/SKILLS.md`);await this.vault.create(l,U({},e.skillsBody||""));let c=(0,N.normalizePath)(`${s}/CONTEXT.md`);await this.vault.create(c,U({},e.contextBody||""));let d=e.permissionRules;if(d&&(d.allow.length>0||d.deny.length>0)){let u=(0,N.normalizePath)(`${s}/permissions.json`);await this.vault.create(u,JSON.stringify(d,null,2)+`
|
|
11648
|
+
`)}return await this.store.loadFile(r),r}async createSkillTemplate(e){let t=await _t(this.vault,this.deps.getSubfolder("skills"),z(e)),s=`---
|
|
11649
|
+
name: ${z(e)}
|
|
11686
11650
|
description:
|
|
11687
11651
|
tags: []
|
|
11688
11652
|
---
|
|
11689
11653
|
|
|
11690
11654
|
Skill instructions go here.
|
|
11691
|
-
|
|
11655
|
+
`,n=await this.vault.create(t,s);return await this.store.loadFile(n),n}async createSkillFolder(e){let t=(0,N.normalizePath)(`${this.deps.getSubfolder("skills")}/${z(e.name)}`);await fe(this.vault,t);let s={name:e.name,description:e.description||void 0,tags:e.tags.length>0?e.tags:void 0},n=(0,N.normalizePath)(`${t}/skill.md`);if(await We(this.vault,n,U(s,e.body||"Skill instructions go here.")),e.toolsBody){let r=(0,N.normalizePath)(`${t}/tools.md`);await We(this.vault,r,`# Tools
|
|
11692
11656
|
|
|
11693
|
-
${
|
|
11657
|
+
${e.toolsBody}`)}if(e.referencesBody){let r=(0,N.normalizePath)(`${t}/references.md`);await We(this.vault,r,`# References
|
|
11694
11658
|
|
|
11695
|
-
${
|
|
11659
|
+
${e.referencesBody}`)}if(e.examplesBody){let r=(0,N.normalizePath)(`${t}/examples.md`);await We(this.vault,r,`# Examples
|
|
11696
11660
|
|
|
11697
|
-
${
|
|
11698
|
-
`;
|
|
11699
|
-
`;
|
|
11661
|
+
${e.examplesBody}`)}await this.store.loadFile(n)}async updateAgent(e,t){let s=this.store.getAgentByName(e);if(s){if(s.isFolder){let n=(0,N.normalizePath)(s.filePath.replace(/\/agent\.md$/,"")),r=this.vault.getAbstractFileByPath(s.filePath);if(r instanceof N.TFile){let l=await this.vault.cachedRead(r),{frontmatter:c,body:d}=W(l);t.description!==void 0&&(c.description=t.description||void 0),t.avatar!==void 0&&(c.avatar=t.avatar||void 0),t.tags!==void 0&&(c.tags=t.tags),t.skills!==void 0&&(c.skills=t.skills),t.mcpServers!==void 0&&(c.mcp_servers=t.mcpServers.length>0?t.mcpServers:void 0),t.enabled!==void 0&&(c.enabled=t.enabled),t.model!==void 0&&t.model!=="default"&&(c.model=t.model);let u=t.systemPrompt!==void 0?t.systemPrompt:d;await this.vault.modify(r,U(c,u))}let i=(0,N.normalizePath)(`${n}/config.md`),o=this.vault.getAbstractFileByPath(i);if(o instanceof N.TFile){let l=await this.vault.cachedRead(o),{frontmatter:c,body:d}=W(l);t.model!==void 0&&(c.model=t.model),t.adapter!==void 0&&(c.adapter=t.adapter),t.timeout!==void 0&&(c.timeout=t.timeout),t.cwd!==void 0&&(c.cwd=t.cwd),t.permissionMode!==void 0&&(c.permission_mode=t.permissionMode),t.effort!==void 0&&(c.effort=t.effort||void 0),t.approvalRequired!==void 0&&(c.approval_required=t.approvalRequired),t.memory!==void 0&&(c.memory=t.memory),t.memoryTokenBudget!==void 0&&(c.memory_token_budget=t.memoryTokenBudget),t.reflectionEnabled!==void 0&&(c.reflection_enabled=t.reflectionEnabled),t.reflectionSchedule!==void 0&&(c.reflection_schedule=t.reflectionSchedule),t.reflectionProposeSkills!==void 0&&(c.reflection_propose_skills=t.reflectionProposeSkills),t.autoCompactThreshold!==void 0&&(c.auto_compact_threshold=t.autoCompactThreshold),t.wikiReferences!==void 0&&(c.wiki_references=t.wikiReferences.length>0?t.wikiReferences.map(u=>({agent:u})):void 0),delete c.allowed_tools,delete c.blocked_tools,await this.vault.modify(o,U(c,d))}if(t.skillsBody!==void 0){let l=(0,N.normalizePath)(`${n}/SKILLS.md`),c=this.vault.getAbstractFileByPath(l);c instanceof N.TFile?await this.vault.modify(c,U({},t.skillsBody)):await this.vault.create(l,U({},t.skillsBody))}if(t.contextBody!==void 0){let l=(0,N.normalizePath)(`${n}/CONTEXT.md`),c=this.vault.getAbstractFileByPath(l);c instanceof N.TFile?await this.vault.modify(c,U({},t.contextBody)):await this.vault.create(l,U({},t.contextBody))}if(t.permissionRules!==void 0){let l=(0,N.normalizePath)(`${n}/permissions.json`),c=this.vault.getAbstractFileByPath(l),d=t.permissionRules;if(d.allow.length>0||d.deny.length>0){let u=JSON.stringify(d,null,2)+`
|
|
11662
|
+
`;c instanceof N.TFile?await this.vault.modify(c,u):await this.vault.create(l,u)}else c instanceof N.TFile&&await this.app.fileManager.trashFile(c)}}else{let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof N.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);t.description!==void 0&&(i.description=t.description||void 0),t.avatar!==void 0&&(i.avatar=t.avatar||void 0),t.tags!==void 0&&(i.tags=t.tags),t.skills!==void 0&&(i.skills=t.skills),t.mcpServers!==void 0&&(i.mcp_servers=t.mcpServers.length>0?t.mcpServers:void 0),t.enabled!==void 0&&(i.enabled=t.enabled),t.model!==void 0&&(i.model=t.model),t.adapter!==void 0&&(i.adapter=t.adapter),t.timeout!==void 0&&(i.timeout=t.timeout),t.cwd!==void 0&&(i.cwd=t.cwd),t.permissionMode!==void 0&&(i.permission_mode=t.permissionMode),t.effort!==void 0&&(i.effort=t.effort||void 0),t.approvalRequired!==void 0&&(i.approval_required=t.approvalRequired),t.memory!==void 0&&(i.memory=t.memory),t.autoCompactThreshold!==void 0&&(i.auto_compact_threshold=t.autoCompactThreshold),t.wikiReferences!==void 0&&(i.wiki_references=t.wikiReferences.length>0?t.wikiReferences.map(c=>({agent:c})):void 0),delete i.allowed_tools,delete i.blocked_tools;let l=t.systemPrompt!==void 0?t.systemPrompt:o;if(await this.vault.modify(n,U(i,l)),t.permissionRules!==void 0){let c=Os(s.filePath),d=this.vault.getAbstractFileByPath(c),u=t.permissionRules;if(u.allow.length>0||u.deny.length>0){let h=JSON.stringify(u,null,2)+`
|
|
11663
|
+
`;d instanceof N.TFile?await this.vault.modify(d,h):await this.vault.create(c,h)}else d instanceof N.TFile&&await this.app.fileManager.trashFile(d)}}await this.store.loadFile(s.filePath)}}async updateTask(e,t){let s=this.store.getTaskById(e);if(!s)return;let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof N.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);t.agent!==void 0&&(i.agent=t.agent),t.type!==void 0&&(i.type=t.type),t.schedule!==void 0&&(i.schedule=t.schedule||void 0),t.runAt!==void 0&&(i.run_at=t.runAt||void 0),t.enabled!==void 0&&(i.enabled=t.enabled),t.priority!==void 0&&(i.priority=t.priority),t.catch_up!==void 0&&(i.catch_up=t.catch_up),t.effort!==void 0&&(i.effort=t.effort||void 0),t.model!==void 0&&(i.model=t.model||void 0),t.channel!==void 0&&(i.channel=t.channel||void 0),t.channelTarget!==void 0&&(i.channel_target=t.channelTarget||void 0),t.tags!==void 0&&(i.tags=t.tags);let l=t.body!==void 0?t.body:o;await this.vault.modify(n,U(i,l)),await this.store.loadFile(n)}async updateSkill(e,t){let s=this.store.getSkillByName(e);if(s){if(s.isFolder){let n=(0,N.normalizePath)(s.filePath.replace(/\/skill\.md$/,"")),r=this.vault.getAbstractFileByPath(s.filePath);if(r instanceof N.TFile){let i=await this.vault.cachedRead(r),{frontmatter:o,body:l}=W(i);t.description!==void 0&&(o.description=t.description||void 0),t.tags!==void 0&&(o.tags=t.tags.length>0?t.tags:void 0);let c=t.body!==void 0?t.body:l;await this.vault.modify(r,U(o,c))}if(t.toolsBody!==void 0){let i=(0,N.normalizePath)(`${n}/tools.md`),o=this.vault.getAbstractFileByPath(i);t.toolsBody&&(o instanceof N.TFile?await this.vault.modify(o,`# Tools
|
|
11700
11664
|
|
|
11701
|
-
${
|
|
11665
|
+
${t.toolsBody}`):await this.vault.create(i,`# Tools
|
|
11702
11666
|
|
|
11703
|
-
${
|
|
11667
|
+
${t.toolsBody}`))}if(t.referencesBody!==void 0){let i=(0,N.normalizePath)(`${n}/references.md`),o=this.vault.getAbstractFileByPath(i);t.referencesBody&&(o instanceof N.TFile?await this.vault.modify(o,`# References
|
|
11704
11668
|
|
|
11705
|
-
${
|
|
11669
|
+
${t.referencesBody}`):await this.vault.create(i,`# References
|
|
11706
11670
|
|
|
11707
|
-
${
|
|
11671
|
+
${t.referencesBody}`))}if(t.examplesBody!==void 0){let i=(0,N.normalizePath)(`${n}/examples.md`),o=this.vault.getAbstractFileByPath(i);t.examplesBody&&(o instanceof N.TFile?await this.vault.modify(o,`# Examples
|
|
11708
11672
|
|
|
11709
|
-
${
|
|
11673
|
+
${t.examplesBody}`):await this.vault.create(i,`# Examples
|
|
11710
11674
|
|
|
11711
|
-
${e.examplesBody}`))}}else{let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof x.TFile))return;let a=await this.vault.cachedRead(n),{frontmatter:i,body:o}=J(a);e.description!==void 0&&(i.description=e.description||void 0),e.tags!==void 0&&(i.tags=e.tags.length>0?e.tags:void 0);let c=e.body!==void 0?e.body:o;await this.vault.modify(n,H(i,c))}}async deleteSkill(t){let e=this.getSkillByName(t);if(e)if(e.isFolder){let s=(0,x.normalizePath)(e.filePath.replace(/\/skill\.md$/,"")),n=this.vault.getAbstractFileByPath(s);n instanceof x.TFolder&&await this.app.fileManager.trashFile(n)}else await this.trashFile(e.filePath)}async deleteTask(t){let e=this.getTaskById(t);e&&await this.trashFile(e.filePath)}async updateChannel(t,e){let s=this.getChannelByName(t);if(!s)return;let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof x.TFile))return;let a=await this.vault.cachedRead(n),{frontmatter:i,body:o}=J(a);e.default_agent!==void 0&&(i.default_agent=e.default_agent,delete i.agent),e.allowed_agents!==void 0&&(i.allowed_agents=e.allowed_agents),e.enabled!==void 0&&(i.enabled=e.enabled),e.credential_ref!==void 0&&(i.credential_ref=e.credential_ref),e.allowed_users!==void 0&&(i.allowed_users=e.allowed_users),e.per_user_sessions!==void 0&&(i.per_user_sessions=e.per_user_sessions),e.channel_context!==void 0&&(i.channel_context=e.channel_context||void 0),e.tags!==void 0&&(i.tags=e.tags),e.type!==void 0&&(i.type=e.type),e.transport!==void 0&&(i.transport=e.transport);let c=e.body!==void 0?e.body:o;await this.vault.modify(n,H(i,c))}async deleteChannel(t){let e=this.getChannelByName(t);if(!e)return;await this.trashFile(e.filePath);let s=(0,x.normalizePath)(`${this.getSubfolder("channels")}/${oe(t)}/sessions`),n=this.vault.getAbstractFileByPath(s);n instanceof x.TFolder&&await this.app.fileManager.trashFile(n)}mcpServerFrontmatter(t){let e={name:t.name,transport:t.type,enabled:t.enabled};return t.source&&(e.source=t.source),t.type==="stdio"?(t.command&&(e.command=t.command),t.args&&t.args.length>0&&(e.args=t.args),t.env&&Object.keys(t.env).length>0&&(e.env=t.env),t.envSecretKeys&&t.envSecretKeys.length>0&&(e.env_secret_keys=t.envSecretKeys)):(t.url&&(e.url=t.url),t.headers&&Object.keys(t.headers).length>0&&(e.headers=t.headers),t.auth&&(e.auth=t.auth),t.oauth&&(t.oauth.clientId||t.oauth.resource||(t.oauth.scopes?.length??0)>0)&&(e.oauth={client_id:t.oauth.clientId||void 0,resource:t.oauth.resource||void 0,scopes:t.oauth.scopes&&t.oauth.scopes.length>0?t.oauth.scopes:void 0})),e}async saveMcpServer(t,e=""){let s=this.mcpServerFrontmatter(t),n=H(s,e.trim()),a=t.filePath?this.vault.getAbstractFileByPath(t.filePath):null;if(a instanceof x.TFile)return await this.vault.modify(a,n),a.path;let i=await this.getAvailablePath(this.getSubfolder("mcp"),oe(t.name));return await this.ensureFolder(this.getSubfolder("mcp")),await this.vault.create(i,n),i}async setMcpServerEnabled(t,e){let s=this.getMcpServerByName(t);if(!s?.filePath)return;let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof x.TFile))return;let a=await this.vault.cachedRead(n),{frontmatter:i,body:o}=J(a);i.enabled=e,await this.vault.modify(n,H(i,o))}async deleteMcpServer(t){let e=this.getMcpServerByName(t);e?.filePath&&await this.trashFile(e.filePath)}async updateHeartbeat(t,e){let s=this.getAgentByName(t);if(!s||!s.isFolder)return;let n=(0,x.normalizePath)(s.filePath.replace(/\/agent\.md$/,"")),a=(0,x.normalizePath)(`${n}/HEARTBEAT.md`),i=this.vault.getAbstractFileByPath(a);if(i instanceof x.TFile){let o=await this.vault.cachedRead(i),{frontmatter:c,body:l}=J(o);e.enabled!==void 0&&(c.enabled=e.enabled),e.schedule!==void 0&&(c.schedule=e.schedule||void 0),e.notify!==void 0&&(c.notify=e.notify),e.channel!==void 0&&(c.channel=e.channel||void 0),e.channelTarget!==void 0&&(c.channel_target=e.channelTarget||void 0);let h=e.body!==void 0?e.body:l;await this.vault.modify(i,H(c,h))}else{let o={enabled:e.enabled??!1};e.schedule&&(o.schedule=e.schedule),e.notify!==void 0&&(o.notify=e.notify),e.channel&&(o.channel=e.channel),e.channelTarget&&(o.channel_target=e.channelTarget);let c=e.body??"";await this.vault.create(a,H(o,c))}}async deleteAgent(t,e){let s=[],n=this.getAgentByName(t);if(!n)return{trashedFiles:s};if(n.isFolder){let c=(0,x.normalizePath)(n.filePath.replace(/\/agent\.md$/,"")),l=this.vault.getAbstractFileByPath(c);if(l instanceof x.TFolder){let h=[];this.collectMarkdownChildren(l,h);for(let d of h)s.push(d.path);await this.app.fileManager.trashFile(l)}}else await this.trashFile(n.filePath),s.push(n.filePath);let a=this.getMemoryPath(t);this.vault.getAbstractFileByPath(a)&&(await this.trashFile(a),s.push(a));let i=this.getMemoryDir(t),o=this.vault.getAbstractFileByPath(i);if(o instanceof x.TFolder&&(await this.app.fileManager.trashFile(o),s.push(i)),e){let c=this.getTasksForAgent(t);for(let l of c)await this.trashFile(l.filePath),s.push(l.filePath)}return{trashedFiles:s}}async trashFile(t){let e=this.vault.getAbstractFileByPath(t);e&&await this.app.fileManager.trashFile(e)}async ensureFolder(t){if(!this.vault.getAbstractFileByPath(t))try{await this.vault.createFolder(t)}catch(e){if(!(e instanceof Error?e.message:String(e)).includes("Folder already exists"))throw e}}async getAvailablePath(t,e){let s=0;for(;;){let n=s===0?"":`-${s+1}`,a=(0,x.normalizePath)(`${t}/${e}${n}.md`);if(!this.vault.getAbstractFileByPath(a))return a;s+=1}}async createFileIfMissing(t,e){if(!this.vault.getAbstractFileByPath(t))try{await this.vault.create(t,e)}catch(s){if(!(s instanceof Error?s.message:String(s)).includes("File already exists"))throw s}}collectMarkdownChildren(t,e){for(let s of t.children)s instanceof x.TFile&&s.extension==="md"&&e.push(s),s instanceof x.TFolder&&this.collectMarkdownChildren(s,e)}clearStoredFile(t){this.agents.delete(t),this.skills.delete(t),this.tasks.delete(t),this.channels.delete(t),this.mcpServers.delete(t),this.validationIssues.delete(t)}setIssue(t,e){let s=this.validationIssues.get(t)??[];s.push({path:t,message:e}),this.validationIssues.set(t,s)}parseFile(t,e){return t.startsWith(`${this.getSubfolder("agents")}/`)?this.parseAgent(t,e):t.startsWith(`${this.getSubfolder("skills")}/`)?this.parseSkill(t,e):t.startsWith(`${this.getSubfolder("tasks")}/`)?this.parseTask(t,e):null}parseAgent(t,e){let{frontmatter:s,body:n}=J(e);if(!Ht(s))return this.setIssue(t,"Invalid frontmatter."),null;let a=A(s.name),i=A(s.model)??this.settings.defaultModel;if(!a||!i)return this.setIssue(t,"Agent requires string field `name` and a valid model or default model setting."),null;let o=ue(s.allowed_tools),c=ue(s.blocked_tools);return(o.length>0||c.length>0)&&!this.warnedLegacyPerms.has(a)&&(this.warnedLegacyPerms.add(a),console.warn(`Agent Fleet: "${a}" still uses legacy allowed_tools/blocked_tools in its frontmatter. Permission rules now live in <name>.permissions.json beside the .md. Open Edit and Save to migrate.`)),{filePath:t,name:a,description:A(s.description),model:i,adapter:A(s.adapter)??"claude-code",permissionMode:A(s.permission_mode)??"bypassPermissions",effort:A(s.effort),maxRetries:Re(s.max_retries,1),skills:ue(s.skills),mcpServers:ue(s.mcp_servers),cwd:A(s.cwd),enabled:Be(s.enabled,!0),timeout:Re(s.timeout,300),approvalRequired:ue(s.approval_required),memory:Be(s.memory,!1),memoryMaxEntries:Re(s.memory_max_entries,100),memoryTokenBudget:Pr(s),reflection:Rr(s),autoCompactThreshold:Re(s.auto_compact_threshold,85),tags:ue(s.tags),avatar:A(s.avatar)??"",body:n,contextBody:"",skillsBody:"",env:this.parseEnvMap(s.env),permissionRules:{allow:o,deny:c},isFolder:!1,heartbeatEnabled:!1,heartbeatSchedule:"",heartbeatBody:"",heartbeatNotify:!0,heartbeatChannel:"",heartbeatChannelTarget:""}}parseSkill(t,e){let{frontmatter:s,body:n}=J(e),a=A(s.name);return a?{filePath:t,name:a,description:A(s.description),tags:ue(s.tags),body:n,toolsBody:"",referencesBody:"",examplesBody:"",isFolder:!1}:(this.setIssue(t,"Skill requires string field `name`."),null)}parseTask(t,e){let{frontmatter:s,body:n}=J(e),a=A(s.task_id),i=A(s.agent),o=A(s.type);if(!a||!i||!o)return this.setIssue(t,"Task requires `task_id`, `agent`, and `type`."),null;if(o==="recurring"&&!A(s.schedule))return this.setIssue(t,"Recurring task requires `schedule`."),null;if(o==="once"&&!A(s.run_at))return this.setIssue(t,"One-time task requires `run_at`."),null;let c=A(s.priority),h=c&&["low","medium","high","critical"].includes(c)?c:"medium";return{filePath:t,taskId:a,agent:i,schedule:A(s.schedule),runAt:A(s.run_at),type:o,priority:h,enabled:Be(s.enabled,!0),created:A(s.created)??new Date().toISOString(),lastRun:A(s.last_run),nextRun:A(s.next_run),runCount:Re(s.run_count,0),catchUp:Be(s.catch_up,this.settings.catchUpMissedTasks),effort:A(s.effort),model:A(s.model),channel:A(s.channel),channelTarget:A(s.channel_target),tags:ue(s.tags),body:n}}parseChannelFile(t,e){let{frontmatter:s,body:n}=J(e),a=A(s.name);if(!a)return this.setIssue(t,"Channel requires string field `name`."),null;let i=A(s.type),o=["slack","telegram","discord"];if(!i||!o.includes(i))return this.setIssue(t,`Channel \`${a}\` requires \`type\` to be one of: ${o.join(", ")}.`),null;let c=i,l=A(s.default_agent)??A(s.agent);if(!l)return this.setIssue(t,`Channel \`${a}\` requires \`default_agent\` (or \`agent\`).`),null;let h=ue(s.allowed_agents),d=A(s.credential_ref);if(!d)return this.setIssue(t,`Channel \`${a}\` requires \`credential_ref\` pointing at a configured credential.`),null;let u=Ht(s.transport)?s.transport:{};return{filePath:t,name:a,type:c,defaultAgent:l,allowedAgents:h,enabled:Be(s.enabled,!0),credentialRef:d,allowedUsers:ue(s.allowed_users),perUserSessions:Be(s.per_user_sessions,!0),channelContext:A(s.channel_context)??"",transport:u,tags:ue(s.tags),body:n}}parseMcpServerFile(t,e){let{frontmatter:s,body:n}=J(e),a=A(s.name);if(!a)return this.setIssue(t,"MCP server requires string field `name`."),null;let i=(A(s.transport)??A(s.type)??"").toLowerCase(),o=["stdio","http","sse"];if(!o.includes(i))return this.setIssue(t,`MCP server \`${a}\` requires \`transport\` to be one of: ${o.join(", ")}.`),null;let c=i;if(c==="stdio"){if(!A(s.command))return this.setIssue(t,`MCP server \`${a}\` (stdio) requires a \`command\`.`),null}else if(!A(s.url))return this.setIssue(t,`MCP server \`${a}\` (${c}) requires a \`url\`.`),null;let l=(A(s.auth)??"").toLowerCase(),h=l==="bearer"||l==="oauth"||l==="none"?l:void 0,d;if(Ht(s.oauth)){let u=s.oauth;d={clientId:A(u.client_id)??A(u.clientId),resource:A(u.resource),scopes:ue(u.scopes)}}return{name:a,filePath:t,type:c,enabled:Be(s.enabled,!0),description:A(s.description)??(n.trim()||void 0),source:A(s.source)==="imported"?"imported":"manual",command:A(s.command),args:ue(s.args),env:Ar(s.env),envSecretKeys:ue(s.env_secret_keys),url:A(s.url),headers:Ar(s.headers),auth:h,oauth:d,status:"disconnected",scope:"user",tools:[],toolDetails:[]}}validateReferences(){let t=new Set;for(let o of this.skills.values())t.has(o.name)&&this.setIssue(o.filePath,`Duplicate skill name \`${o.name}\`.`),t.add(o.name);let e=new Set;for(let o of this.agents.values()){e.has(o.name)&&this.setIssue(o.filePath,`Duplicate agent name \`${o.name}\`.`),e.add(o.name);for(let c of o.skills)t.has(c)||this.setIssue(o.filePath,`Agent references missing skill \`${c}\`.`)}for(let o of this.tasks.values())e.has(o.agent)||this.setIssue(o.filePath,`Task references missing agent \`${o.agent}\`.`);let s=new Set,n=new Map;for(let o of this.agents.values())n.set(o.name,o);let a=this.channelCredentialGetter?.()??this.settings.channelCredentials??{};for(let o of this.channels.values()){s.has(o.name)&&this.setIssue(o.filePath,`Duplicate channel name \`${o.name}\`.`),s.add(o.name);let c=n.get(o.defaultAgent);c?c.approvalRequired.length>0&&this.setIssue(o.filePath,`Channel \`${o.name}\` cannot bind to agent \`${c.name}\` because the agent has \`approval_required\` set (${c.approvalRequired.join(", ")}). Clear the approval list on the agent or pick a different agent.`):this.setIssue(o.filePath,`Channel \`${o.name}\` references missing agent \`${o.defaultAgent}\`.`);let l=a[o.credentialRef];l?l.type!==o.type&&this.setIssue(o.filePath,`Channel \`${o.name}\` is type \`${o.type}\` but credential \`${o.credentialRef}\` is type \`${l.type}\`.`):this.setIssue(o.filePath,`Channel \`${o.name}\` references missing credential \`${o.credentialRef}\`. Add it under Settings \u2192 Channel Credentials.`)}let i=new Set;for(let o of this.mcpServers.values())i.has(o.name)&&this.setIssue(o.filePath??o.name,`Duplicate MCP server name \`${o.name}\`.`),i.add(o.name)}parseEnvMap(t){if(!Ht(t))return{};let e={};for(let[s,n]of Object.entries(t))typeof n=="string"?e[s]=n:(typeof n=="number"||typeof n=="boolean")&&(e[s]=String(n));return e}parseApprovals(t){if(Array.isArray(t))return t.flatMap(e=>{if(!Ht(e)||!A(e.tool))return[];let s=A(e.tool);return s?[{tool:s,command:A(e.command),reason:A(e.reason),status:A(e.status)??"pending",resolvedAt:A(e.resolvedAt),note:A(e.note)}]:[]})}};var Pt=require("obsidian"),Ks=class extends Pt.Modal{constructor(e,s,n){super(e);this.info=s;this.onConfirm=n}deleteTasks=!0;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("af-confirm-delete-modal");let s=e.createDiv({cls:"af-delete-header"}),n=s.createSpan({cls:"af-delete-header-icon"});(0,Pt.setIcon)(n,"alert-triangle"),s.createEl("h3",{text:`Delete agent "${this.info.agentName}"?`});let a=e.createDiv({cls:"af-delete-summary"});a.createDiv({text:"This action will:"});let i=a.createEl("ul",{cls:"af-delete-impact-list"});i.createEl("li",{text:"Move the agent definition to trash"}),this.info.hasMemory&&i.createEl("li",{text:"Move the agent's memory file to trash"}),this.info.taskCount>0&&i.createEl("li").setText(`${this.info.taskCount} task${this.info.taskCount!==1?"s":""} reference this agent`),this.info.runCount>0&&i.createEl("li",{cls:"af-delete-preserved"}).setText(`${this.info.runCount} run log${this.info.runCount!==1?"s":""} will be preserved`),e.createDiv({cls:"af-delete-note",text:"Files are moved to your system trash and can be recovered."}),this.info.taskCount>0&&new Pt.Setting(e).setName("Also delete associated tasks").setDesc(`Delete ${this.info.taskCount} task${this.info.taskCount!==1?"s":""} that reference this agent`).addToggle(d=>{d.setValue(this.deleteTasks),d.onChange(u=>{this.deleteTasks=u})});let o=e.createDiv({cls:"af-delete-actions"}),c=o.createEl("button",{text:"Cancel"});c.onclick=()=>this.close();let l=o.createEl("button",{cls:"af-delete-confirm-btn",text:"Delete Agent"}),h=l.createSpan({cls:"af-delete-btn-icon"});(0,Pt.setIcon)(h,"trash-2"),l.onclick=()=>{this.onConfirm(this.deleteTasks),this.close()}}};var F=require("obsidian");var Js=require("obsidian"),qt=class extends Js.Modal{constructor(e,s){super(e);this.opts=s}onOpen(){let{contentEl:e}=this;e.empty(),e.createEl("h3",{text:this.opts.title});for(let s of this.opts.body.split(`
|
|
11675
|
+
${t.examplesBody}`))}}else{let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof N.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);t.description!==void 0&&(i.description=t.description||void 0),t.tags!==void 0&&(i.tags=t.tags.length>0?t.tags:void 0);let l=t.body!==void 0?t.body:o;await this.vault.modify(n,U(i,l))}await this.store.loadFile(s.filePath)}}async deleteSkill(e){let t=this.store.getSkillByName(e);if(t){if(t.isFolder){let s=(0,N.normalizePath)(t.filePath.replace(/\/skill\.md$/,"")),n=this.vault.getAbstractFileByPath(s);n instanceof N.TFolder&&await this.app.fileManager.trashFile(n),this.store.clearIssuesUnder(s)}else await qe(this.app,t.filePath);this.store.clearStoredFile(t.filePath),this.store.validateReferences()}}async deleteTask(e){let t=this.store.getTaskById(e);t&&(await qe(this.app,t.filePath),this.store.clearStoredFile(t.filePath),this.store.validateReferences())}async updateChannel(e,t){let s=this.store.getChannelByName(e);if(!s)return;let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof N.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);t.default_agent!==void 0&&(i.default_agent=t.default_agent,delete i.agent),t.allowed_agents!==void 0&&(i.allowed_agents=t.allowed_agents),t.enabled!==void 0&&(i.enabled=t.enabled),t.credential_ref!==void 0&&(i.credential_ref=t.credential_ref),t.allowed_users!==void 0&&(i.allowed_users=t.allowed_users),t.per_user_sessions!==void 0&&(i.per_user_sessions=t.per_user_sessions),t.channel_context!==void 0&&(i.channel_context=t.channel_context||void 0),t.tags!==void 0&&(i.tags=t.tags),t.type!==void 0&&(i.type=t.type),t.transport!==void 0&&(i.transport=t.transport);let l=t.body!==void 0?t.body:o;await this.vault.modify(n,U(i,l)),await this.store.loadFile(n)}async deleteChannel(e){let t=this.store.getChannelByName(e);if(!t)return;await qe(this.app,t.filePath),this.store.clearStoredFile(t.filePath),this.store.validateReferences();let s=(0,N.normalizePath)(`${this.deps.getSubfolder("channels")}/${z(e)}/sessions`),n=this.vault.getAbstractFileByPath(s);n instanceof N.TFolder&&await this.app.fileManager.trashFile(n)}async updateHeartbeat(e,t){let s=this.store.getAgentByName(e);if(!s||!s.isFolder)return;let n=(0,N.normalizePath)(s.filePath.replace(/\/agent\.md$/,"")),r=(0,N.normalizePath)(`${n}/HEARTBEAT.md`),i=this.vault.getAbstractFileByPath(r);if(i instanceof N.TFile){let o=await this.vault.cachedRead(i),{frontmatter:l,body:c}=W(o);t.enabled!==void 0&&(l.enabled=t.enabled),t.schedule!==void 0&&(l.schedule=t.schedule||void 0),t.notify!==void 0&&(l.notify=t.notify),t.channel!==void 0&&(l.channel=t.channel||void 0),t.channelTarget!==void 0&&(l.channel_target=t.channelTarget||void 0);let d=t.body!==void 0?t.body:c;await this.vault.modify(i,U(l,d))}else{let o={enabled:t.enabled??!1};t.schedule&&(o.schedule=t.schedule),t.notify!==void 0&&(o.notify=t.notify),t.channel&&(o.channel=t.channel),t.channelTarget&&(o.channel_target=t.channelTarget);let l=t.body??"";await this.vault.create(r,U(o,l))}await this.store.loadFile(r)}async deleteAgent(e,t){let s=[],n=this.store.getAgentByName(e);if(!n)return{trashedFiles:s};if(n.isFolder){let l=(0,N.normalizePath)(n.filePath.replace(/\/agent\.md$/,"")),c=this.vault.getAbstractFileByPath(l);if(c instanceof N.TFolder){let d=[];ps(c,d);for(let u of d)s.push(u.path);await this.app.fileManager.trashFile(c)}this.store.clearIssuesUnder(l)}else await qe(this.app,n.filePath),s.push(n.filePath),this.store.clearIssuesFor(Os(n.filePath));this.store.clearStoredFile(n.filePath);let r=this.deps.getMemoryPath(e);this.vault.getAbstractFileByPath(r)&&(await qe(this.app,r),s.push(r));let i=this.deps.getMemoryDir(e),o=this.vault.getAbstractFileByPath(i);if(o instanceof N.TFolder&&(await this.app.fileManager.trashFile(o),s.push(i)),t){let l=this.store.getTasksForAgent(e);for(let c of l)await qe(this.app,c.filePath),s.push(c.filePath),this.store.clearStoredFile(c.filePath)}return this.store.validateReferences(),{trashedFiles:s}}};var Ce=require("obsidian");var Ns=class extends Map{constructor(t){super();this.onMutate=t}set(t,s){return this.onMutate(),super.set(t,s)}delete(t){return this.onMutate(),super.delete(t)}clear(){this.onMutate(),super.clear()}},Cn=class{constructor(e,t){this.deps=t;this.vault=e.vault,this.settings=t.settings,this.parserCtx={vault:this.vault,settings:this.settings,reportIssue:(s,n)=>this.setIssue(s,n),clearIssue:s=>{this.validationIssues.delete(s)},warnedLegacyPerms:this.warnedLegacyPerms,warnedFolderAgentModelConflict:this.warnedFolderAgentModelConflict}}agents=new Ns(()=>{this.nameIndexesStale=!0});skills=new Ns(()=>{this.nameIndexesStale=!0});tasks=new Ns(()=>{this.nameIndexesStale=!0});channels=new Map;mcpServers=new Map;validationIssues=new Map;referenceIssues=new Map;bulkLoading=!1;nameIndexesStale=!0;agentsByName=new Map;skillsByName=new Map;tasksById=new Map;channelCredentialGetter;warnedFolderAgentModelConflict=new Set;warnedLegacyPerms=new Set;vault;settings;parserCtx;setChannelCredentialGetter(e){this.channelCredentialGetter=e}async loadAll(){this.agents.clear(),this.skills.clear(),this.tasks.clear(),this.channels.clear(),this.mcpServers.clear(),this.validationIssues.clear(),this.referenceIssues.clear(),this.bulkLoading=!0;try{await this.loadFolderAgents(),await this.loadFolderSkills();let e=this.vault.getMarkdownFiles().filter(t=>t.path.startsWith(`${this.deps.getFleetRoot()}/`));for(let t of e)await this.loadFile(t)}finally{this.bulkLoading=!1}return this.validateReferences(),this.getSnapshot()}async loadFile(e){await this.loadFileInternal(e),this.bulkLoading||this.validateReferences()}async loadFileInternal(e){let t=typeof e=="string"?this.vault.getAbstractFileByPath(e):e;if(!(t instanceof Ce.TFile)||t.extension!=="md")return;if(this.isInsideAgentFolder(t.path)){await this.reloadFolderAgentContaining(t.path);return}if(this.isInsideSkillFolder(t.path)){await this.reloadFolderSkillContaining(t.path);return}this.clearStoredFile(t.path);let s=`${this.deps.getSubfolder("channels")}/`;if(t.path.startsWith(s)){if(!t.path.slice(s.length).includes("/")){let l=await this.vault.cachedRead(t),c=oi(this.parserCtx,t.path,l);c&&this.channels.set(t.path,c)}return}let n=`${this.deps.getSubfolder("mcp")}/`;if(t.path.startsWith(n)){if(!t.path.slice(n.length).includes("/")){let l=await this.vault.cachedRead(t),c=this.deps.parseMcpServerFile(t.path,l);c&&this.mcpServers.set(t.path,c)}return}let r=await this.vault.cachedRead(t),i=this.parseFile(t.path,r);if(i)if("taskId"in i)this.tasks.set(t.path,i);else if("model"in i){if(!i.isFolder){let o=Os(t.path);this.validationIssues.delete(o);let l=this.vault.getAbstractFileByPath(o);if(l instanceof Ce.TFile)try{let c=await this.vault.cachedRead(l),d=JSON.parse(c);i.permissionRules={allow:Q(d.allow),deny:Q(d.deny)}}catch(c){console.error(`Agent Fleet: invalid JSON in ${o} \u2014 agent "${i.name}" falls back to legacy frontmatter permission rules`,c),this.setIssue(o,`Invalid JSON in ${o} for agent \`${i.name}\` \u2014 sidecar permission rules are NOT applied.`)}}this.agents.set(t.path,i)}else this.skills.set(t.path,i)}async reloadFolderAgentContaining(e){let t=`${this.deps.getSubfolder("agents")}/`,n=e.slice(t.length).split("/")[0];if(!n)return;let r=(0,Ce.normalizePath)(`${t}${n}`),i=(0,Ce.normalizePath)(`${r}/agent.md`);if(this.agents.delete(i),!(this.vault.getAbstractFileByPath(r)instanceof Ce.TFolder))return;let l=this.vault.getAbstractFileByPath(i);if(!(l instanceof Ce.TFile))return;let c=await Ua(this.parserCtx,r,l);c&&this.agents.set(i,c)}isInsideAgentFolder(e){let t=`${this.deps.getSubfolder("agents")}/`;return e.startsWith(t)?e.slice(t.length).includes("/"):!1}isInsideSkillFolder(e){let t=`${this.deps.getSubfolder("skills")}/`;return e.startsWith(t)?e.slice(t.length).includes("/"):!1}async reloadFolderSkillContaining(e){let t=`${this.deps.getSubfolder("skills")}/`,n=e.slice(t.length).split("/")[0];if(!n)return;let r=(0,Ce.normalizePath)(`${t}${n}`),i=(0,Ce.normalizePath)(`${r}/skill.md`);if(this.skills.delete(i),!(this.vault.getAbstractFileByPath(r)instanceof Ce.TFolder))return;let l=this.vault.getAbstractFileByPath(i);if(!(l instanceof Ce.TFile))return;let c=await Ba(this.parserCtx,r,l);c&&this.skills.set(i,c)}async loadFolderSkills(){let e=this.vault.getAbstractFileByPath(this.deps.getSubfolder("skills"));if(e instanceof Ce.TFolder)for(let t of e.children){if(!(t instanceof Ce.TFolder))continue;let s=(0,Ce.normalizePath)(`${t.path}/skill.md`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof Ce.TFile))continue;let r=await Ba(this.parserCtx,t.path,n);r&&this.skills.set(s,r)}}async loadFolderAgents(){let e=this.vault.getAbstractFileByPath(this.deps.getSubfolder("agents"));if(e instanceof Ce.TFolder)for(let t of e.children){if(!(t instanceof Ce.TFolder))continue;let s=(0,Ce.normalizePath)(`${t.path}/agent.md`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof Ce.TFile))continue;let r=await Ua(this.parserCtx,t.path,n);r&&this.agents.set(s,r)}}removeFile(e){this.clearStoredFile(e),this.bulkLoading||this.validateReferences()}getSnapshot(){return{agents:Array.from(this.agents.values()).sort((e,t)=>e.name.localeCompare(t.name)),skills:Array.from(this.skills.values()).sort((e,t)=>e.name.localeCompare(t.name)),tasks:Array.from(this.tasks.values()).sort((e,t)=>e.taskId.localeCompare(t.taskId)),channels:Array.from(this.channels.values()).sort((e,t)=>e.name.localeCompare(t.name)),mcpServers:Array.from(this.mcpServers.values()).sort((e,t)=>e.name.localeCompare(t.name)),validationIssues:[...Array.from(this.validationIssues.values()).flat(),...Array.from(this.referenceIssues.values()).flat()]}}rebuildNameIndexes(){if(this.nameIndexesStale){this.agentsByName.clear(),this.skillsByName.clear(),this.tasksById.clear();for(let e of this.agents.values())this.agentsByName.has(e.name)||this.agentsByName.set(e.name,e);for(let e of this.skills.values())this.skillsByName.has(e.name)||this.skillsByName.set(e.name,e);for(let e of this.tasks.values())this.tasksById.has(e.taskId)||this.tasksById.set(e.taskId,e);this.nameIndexesStale=!1}}getAgentByName(e){return this.rebuildNameIndexes(),this.agentsByName.get(e)}getSkillByName(e){return this.rebuildNameIndexes(),this.skillsByName.get(e)}getTaskById(e){return this.rebuildNameIndexes(),this.tasksById.get(e)}getTasksForAgent(e){return Array.from(this.tasks.values()).filter(t=>t.agent===e)}getChannelByName(e){return Array.from(this.channels.values()).find(t=>t.name===e)}getChannelsForAgent(e){return Array.from(this.channels.values()).filter(t=>t.defaultAgent===e)}getMcpServers(){return Array.from(this.mcpServers.values()).sort((e,t)=>e.name.localeCompare(t.name))}getMcpServerByName(e){return Array.from(this.mcpServers.values()).find(t=>t.name===e)}clearStoredFile(e){this.agents.delete(e),this.skills.delete(e),this.tasks.delete(e),this.channels.delete(e),this.mcpServers.delete(e),this.validationIssues.delete(e),this.referenceIssues.delete(e)}clearIssuesUnder(e){let t=`${e}/`;for(let s of[...this.validationIssues.keys()])s.startsWith(t)&&this.validationIssues.delete(s);for(let s of[...this.referenceIssues.keys()])s.startsWith(t)&&this.referenceIssues.delete(s)}clearIssuesFor(e){this.validationIssues.delete(e),this.referenceIssues.delete(e)}setIssue(e,t){let s=this.validationIssues.get(e)??[];s.push({path:e,message:t}),this.validationIssues.set(e,s)}setReferenceIssue(e,t){let s=this.referenceIssues.get(e)??[];s.push({path:e,message:t}),this.referenceIssues.set(e,s)}parseFile(e,t){return e.startsWith(`${this.deps.getSubfolder("agents")}/`)?ai(this.parserCtx,e,t):e.startsWith(`${this.deps.getSubfolder("skills")}/`)?ri(this.parserCtx,e,t):e.startsWith(`${this.deps.getSubfolder("tasks")}/`)?ii(this.parserCtx,e,t):null}validateReferences(){this.referenceIssues.clear();let e=new Set;for(let o of this.skills.values())e.has(o.name)&&this.setReferenceIssue(o.filePath,`Duplicate skill name \`${o.name}\`.`),e.add(o.name);let t=new Set;for(let o of this.agents.values()){t.has(o.name)&&this.setReferenceIssue(o.filePath,`Duplicate agent name \`${o.name}\`.`),t.add(o.name);for(let l of o.skills)e.has(l)||this.setReferenceIssue(o.filePath,`Agent references missing skill \`${l}\`.`)}for(let o of this.tasks.values())t.has(o.agent)||this.setReferenceIssue(o.filePath,`Task references missing agent \`${o.agent}\`.`);let s=new Set,n=new Map;for(let o of this.agents.values())n.set(o.name,o);let r=this.channelCredentialGetter?.()??this.settings.channelCredentials??{};for(let o of this.channels.values()){s.has(o.name)&&this.setReferenceIssue(o.filePath,`Duplicate channel name \`${o.name}\`.`),s.add(o.name);let l=n.get(o.defaultAgent);l?l.approvalRequired.length>0&&this.setReferenceIssue(o.filePath,`Channel \`${o.name}\` cannot bind to agent \`${l.name}\` because the agent has \`approval_required\` set (${l.approvalRequired.join(", ")}). Clear the approval list on the agent or pick a different agent.`):this.setReferenceIssue(o.filePath,`Channel \`${o.name}\` references missing agent \`${o.defaultAgent}\`.`);let c=r[o.credentialRef];c?c.type!==o.type&&this.setReferenceIssue(o.filePath,`Channel \`${o.name}\` is type \`${o.type}\` but credential \`${o.credentialRef}\` is type \`${c.type}\`.`):this.setReferenceIssue(o.filePath,`Channel \`${o.name}\` references missing credential \`${o.credentialRef}\`. Add it under Settings \u2192 Channel Credentials.`)}let i=new Set;for(let o of this.mcpServers.values())i.has(o.name)&&this.setReferenceIssue(o.filePath??o.name,`Duplicate MCP server name \`${o.name}\`.`),i.add(o.name)}};var xi=require("path"),ve=require("obsidian");var Kt=2,di=["Preferences","Procedures","Observations","Recent"],ui="Recent",ja=/\[REMEMBER(?::([a-zA-Z]+))?\]([\s\S]*?)\[\/REMEMBER\]/g;function zc(a){switch((a??"").toLowerCase()){case"pin":case"preference":case"preferences":return{pinned:!0,section:"Preferences"};case"procedure":case"procedures":return{pinned:!1,section:"Procedures"};case"observation":case"observations":return{pinned:!1,section:"Observations"};default:return{pinned:!1}}}function Tn(a){let e=[];for(let t of a.matchAll(ja)){let s=(t[2]??"").trim();if(!s)continue;let n=zc(t[1]);e.push({text:s,pinned:n.pinned,section:n.section})}return e}function Jt(a){return a.replace(ja,"").replace(/[ \t]+\n/g,`
|
|
11676
|
+
`).replace(/\n{3,}/g,`
|
|
11712
11677
|
|
|
11713
|
-
`)
|
|
11678
|
+
`).trim()}function hi(a){let e=a.replace(ja,""),t=e.match(/\[REMEMBER(?::[a-zA-Z]+)?\][\s\S]*$/i);if(t&&t.index!==void 0)return e.slice(0,t.index);let s=e.match(/\[(?:R(?:E(?:M(?:E(?:M(?:B(?:E(?:R(?::[a-zA-Z]*)?)?)?)?)?)?)?)?)?$/i);return s&&s.index!==void 0?e.slice(0,s.index):e}var Gc={Preferences:"Preferences",Procedures:"Procedures",Observations:"Observations",Recent:"Recent (uncurated)"};function Vc(a){let e=a.trim().toLowerCase();return e.startsWith("preference")?"Preferences":e.startsWith("procedure")?"Procedures":e.startsWith("observation")?"Observations":e.startsWith("recent")?"Recent":"Observations"}function Bs(a){return Math.ceil(a.length/4)}var li=500;function pi(a){let e=a.replace(/\s+/g," ").trim();return e.length<=li?e:`${e.slice(0,li-1).trimEnd()}\u2026`}function $a(a){return typeof a=="string"?a:void 0}function Yc(a,e){return typeof a=="number"&&Number.isFinite(a)?a:e}function mi(a,e){return{filePath:a,agent:e,schema:Kt,tokenEstimate:0,sections:[]}}var Kc=/\s*<!--\s*([\s\S]*?)\s*-->\s*$/,ci=/^\[pin\]\s+/i;function Jc(a){let e=a.match(/^[-*]\s+(.*)$/);if(!e)return null;let t=(e[1]??"").trim();if(!t)return null;let s,n,r=t.match(Kc);if(r){t=t.slice(0,r.index).trim();let o=(r[1]??"").trim(),l=o.match(/^src:(\S+)(?:\s+(.+))?$/);l?(s=l[1],n=l[2]?.trim()||void 0):o&&(n=o)}let i=!1;return ci.test(t)&&(i=!0,t=t.replace(ci,"").trim()),t?{text:t,source:s,date:n,pinned:i}:null}function fi(a){let e=a.pinned?"[pin] ":"",t="";if(a.source||a.date){let s=[];a.source&&s.push(`src:${a.source}`),a.date&&s.push(a.date),t=` <!-- ${s.join(" ")} -->`}return`- ${e}${a.text}${t}`}function at(a){return Xc(a).map(t=>{let s=t.entries.map(fi).join(`
|
|
11679
|
+
`);return`## ${Gc[t.name]}
|
|
11680
|
+
${s}`}).join(`
|
|
11681
|
+
|
|
11682
|
+
`)}function Xc(a){let e=[];for(let t of di){let s=a.find(n=>n.name===t);s&&s.entries.length>0&&e.push(s)}return e}function gi(a,e,t){let{frontmatter:s,body:n}=W(a),r=_n(n);return{filePath:e,agent:$a(s.agent)??t,schema:Yc(s.schema,Kt),lastUpdated:$a(s.last_updated),lastReflection:$a(s.last_reflection),tokenEstimate:Bs(at(r)),sections:r}}function _n(a){let e=new Map,t=(r,i)=>{let o=e.get(r)??[];o.push(i),e.set(r,o)},s="Observations";for(let r of a.split(`
|
|
11683
|
+
`)){let i=r.match(/^#{1,6}\s+(.+?)\s*$/);if(i){s=Vc(i[1]??"");continue}let o=Jc(r);o&&t(s,o)}let n=[];for(let r of di){let i=e.get(r);i&&i.length&&n.push({name:r,entries:i})}return n}function yi(a){let e=at(a.sections),t={agent:a.agent,schema:a.schema||Kt,last_updated:a.lastUpdated??"",token_estimate:Bs(e)};return a.lastReflection&&(t.last_reflection=a.lastReflection),U(t,e||"## Observations")}function vi(a,e,t,s){if(e.length===0)return a;let n=a.sections.map(o=>({name:o.name,entries:[...o.entries]})),r=n.find(o=>o.name===t);return r||(r={name:t,entries:[]},n.push(r)),r.entries.push(...e),{...a,sections:n,lastUpdated:s??a.lastUpdated,tokenEstimate:Bs(at(n))}}var Qc=["Recent","Observations","Procedures"];function wi(a,e){if(a.tokenEstimate<=e)return{wm:a,spilled:[]};let t=a.sections.map(o=>({name:o.name,entries:[...o.entries]})),s=[],n=at(t).length,r=()=>Math.ceil(n/4)>e;for(let o of Qc){if(!r())break;let l=t.find(c=>c.name===o);if(l)for(;l.entries.length>0&&r();){let c=l.entries.findIndex(u=>!u.pinned);if(c===-1)break;let d=l.entries.splice(c,1)[0];d&&(s.push(d),n-=fi(d).length+1)}}let i=t.filter(o=>o.entries.length>0);return{wm:{...a,sections:i,tokenEstimate:Bs(at(i))},spilled:s}}function Ha(a,e,t,s){let n=_n(a);return{filePath:e,agent:t,schema:Kt,lastUpdated:s,tokenEstimate:Bs(at(n)),sections:n}}function bi(a,e){let t=(a?.sections??[]).flatMap(i=>i.entries).filter(i=>i.pinned);if(t.length===0||e.some(i=>i.entries.some(o=>o.pinned)))return e;let n=e.map(i=>({name:i.name,entries:[...i.entries]})),r=n.find(i=>i.name==="Preferences");return r||(r={name:"Preferences",entries:[]},n.unshift(r)),r.entries.unshift(...t),n}var Zc="When you learn a durable fact about the user, their preferences, or how to do your work better, save it to memory. Prefer the `remember` tool \u2014 call remember(fact, pin?, section?); it is the reliable way to record a memory. If that tool is not available, fall back to writing [REMEMBER] <one concise fact> [/REMEMBER] in your reply (use [REMEMBER:pin] for standing preferences and hard constraints). Record only durable, reusable facts \u2014 not transient task details. These notes persist into your future runs.";function ki(a,e){if(!a.memory)return"";let s=(e?at(e.sections).trim():"")||"Nothing yet \u2014 this is a fresh agent.";return`## Memory
|
|
11684
|
+
${Zc}
|
|
11685
|
+
|
|
11686
|
+
### What you've learned so far
|
|
11687
|
+
${s}`}var An=class{constructor(e,t){this.app=e;this.getMemoryRoot=t;this.vault=e.vault}migratingMemory=new Map;vault;getMemoryPath(e){return(0,ve.normalizePath)(`${this.getMemoryRoot()}/${z(e)}.md`)}getMemoryDir(e){return(0,ve.normalizePath)(`${this.getMemoryRoot()}/${z(e)}`)}getWorkingMemoryPath(e){return(0,ve.normalizePath)(`${this.getMemoryDir(e)}/working.md`)}getRawMemoryPath(e,t){let s=t.slice(0,10);return(0,ve.normalizePath)(`${this.getMemoryDir(e)}/raw/${s}.md`)}async readWorkingMemory(e){let t=this.getWorkingMemoryPath(e),s=this.vault.getAbstractFileByPath(t);if(s instanceof ve.TFile){let i=await this.vault.cachedRead(s);return this.hasIncompatibleSchema(i,t)?null:gi(i,t,e)}let n=this.getMemoryPath(e),r=this.vault.getAbstractFileByPath(n);if(r instanceof ve.TFile){let i=await this.vault.cachedRead(r),{body:o}=W(i);return Ha(o,t,e)}return null}async writeWorkingMemory(e,t){let s=this.getWorkingMemoryPath(e);await fe(this.vault,this.getMemoryDir(e));let n=yi(t),r=this.vault.getAbstractFileByPath(s);if(r instanceof ve.TFile){if(this.hasIncompatibleSchema(await this.vault.cachedRead(r),s))return;await this.vault.modify(r,n)}else await We(this.vault,s,n);let i=this.getMemoryPath(e);i!==s&&this.vault.getAbstractFileByPath(i)&&await qe(this.app,i)}hasIncompatibleSchema(e,t){let{frontmatter:s}=W(e),n=s.schema;return n===void 0||typeof n=="number"&&Number.isFinite(n)&&n<=Kt?!1:(console.warn(`Agent Fleet: ${t} has unrecognized memory schema ${JSON.stringify(n)} (this plugin supports up to ${Kt}) \u2014 treating working memory as unavailable and leaving the file untouched. Update the plugin to use this memory.`),!0)}async migrateLegacyMemory(e){let t=this.migratingMemory.get(e);if(t)return t;let s=this.getWorkingMemoryPath(e);if(this.vault.getAbstractFileByPath(s))return;let n=this.getMemoryPath(e),r=this.vault.getAbstractFileByPath(n);if(!(r instanceof ve.TFile))return;let i=(async()=>{let o=await this.vault.cachedRead(r),{body:l}=W(o),c=new Date().toISOString(),d=l.split(`
|
|
11688
|
+
`).map(p=>p.replace(/^\s*[-*]\s+/,"").trim()).filter(p=>p.length>0&&!/^#{1,6}\s/.test(p)),u=[`- ${c} [migrated] Imported ${d.length} legacy memory entr${d.length===1?"y":"ies"} (pre-v2).`,...d.map(p=>`- ${c} [migrated] ${p}`)];await this.appendRawMemory(e,u,c);let h=Ha(l,s,e,c);await this.writeWorkingMemory(e,h)})();this.migratingMemory.set(e,i);try{await i}finally{this.migratingMemory.delete(e)}}getPendingDir(e){return(0,ve.normalizePath)(`${this.getMemoryDir(e)}/pending`)}getPendingDirAbsolutePath(e){let t=this.vault.adapter;return t instanceof ve.FileSystemAdapter?(0,xi.join)(t.getBasePath(),this.getPendingDir(e)):null}async ensureMemoryDir(e){await fe(this.vault,this.getMemoryDir(e))}async readAndClearPending(e){let t=this.vault.adapter,s=this.getPendingDir(e),n;try{if(!await t.exists(s))return[];n=(await t.list(s)).files}catch{return[]}let r=[];for(let i of n)if(i.endsWith(".json"))try{let o=await t.read(i);await t.remove(i);for(let l of o.split(`
|
|
11689
|
+
`))l.trim().length>0&&r.push(l)}catch(o){console.warn(`Agent Fleet: skipping pending capture file ${i} (retried next drain)`,o)}return r}async readRecentRaw(e,t=2){let s=(0,ve.normalizePath)(`${this.getMemoryDir(e)}/raw`),n=this.vault.getAbstractFileByPath(s);if(!(n instanceof ve.TFolder))return"";let r=n.children.filter(o=>o instanceof ve.TFile&&o.extension==="md").sort((o,l)=>l.name.localeCompare(o.name)).slice(0,t),i=[];for(let o of r.reverse())i.push(`### ${o.basename}
|
|
11690
|
+
${await this.vault.cachedRead(o)}`);return i.join(`
|
|
11691
|
+
|
|
11692
|
+
`)}getCandidatesPath(e){return(0,ve.normalizePath)(`${this.getMemoryDir(e)}/candidates.json`)}async readCandidates(e){let t=this.getCandidatesPath(e),s=this.vault.getAbstractFileByPath(t);if(!(s instanceof ve.TFile))return[];try{let n=JSON.parse(await this.vault.cachedRead(s));return Array.isArray(n)?n:[]}catch(n){return console.warn(`Agent Fleet: invalid JSON in ${t} \u2014 treating skill-candidate ledger as empty`,n),[]}}async writeCandidates(e,t){let s=this.getCandidatesPath(e);await fe(this.vault,this.getMemoryDir(e));let n=JSON.stringify(t,null,2),r=this.vault.getAbstractFileByPath(s);r instanceof ve.TFile?await this.vault.modify(r,n):await We(this.vault,s,n)}async appendRawMemory(e,t,s){if(t.length===0)return;let n=this.getRawMemoryPath(e,s);await fe(this.vault,n.replace(/\/[^/]+$/,""));let r=t.map(o=>o.trimEnd()).join(`
|
|
11693
|
+
`),i=this.vault.getAbstractFileByPath(n);if(i instanceof ve.TFile){let o=await this.vault.cachedRead(i);await this.vault.modify(i,`${o.trimEnd()}
|
|
11694
|
+
${r}
|
|
11695
|
+
`)}else await We(this.vault,n,`${r}
|
|
11696
|
+
`)}async getMemory(e){let t=await this.readWorkingMemory(e);return t?{filePath:t.filePath,agent:t.agent,lastUpdated:t.lastUpdated,body:at(t.sections)}:null}async appendMemory(e,t){if(t.length===0)return;let s=this.getMemoryPath(e),n=this.vault.getAbstractFileByPath(s),r=new Date().toISOString(),i=t.map(o=>`- ${o.trim()}`).join(`
|
|
11697
|
+
`);if(n instanceof ve.TFile){let l=`${(await this.getMemory(e))?.body.trim()||"## Learned Context"}
|
|
11698
|
+
|
|
11699
|
+
${i}`.trim();await this.vault.modify(n,U({agent:e,last_updated:r},l));return}await We(this.vault,s,U({agent:e,last_updated:r},`## Learned Context
|
|
11700
|
+
|
|
11701
|
+
${i}`))}};var Wa=require("obsidian");var Pn=class{constructor(e,t){this.app=e;this.deps=t;this.vault=e.vault}vault;parseMcpServerFile(e,t){let{frontmatter:s,body:n}=W(t),r=C(s.name);if(!r)return this.deps.reportIssue(e,"MCP server requires string field `name`."),null;let i=(C(s.transport)??C(s.type)??"").toLowerCase(),o=["stdio","http","sse"];if(!o.includes(i))return this.deps.reportIssue(e,`MCP server \`${r}\` requires \`transport\` to be one of: ${o.join(", ")}.`),null;let l=i;if(l==="stdio"){if(!C(s.command))return this.deps.reportIssue(e,`MCP server \`${r}\` (stdio) requires a \`command\`.`),null}else if(!C(s.url))return this.deps.reportIssue(e,`MCP server \`${r}\` (${l}) requires a \`url\`.`),null;let c=(C(s.auth)??"").toLowerCase(),d=c==="bearer"||c==="oauth"||c==="none"?c:void 0,u;if(Tt(s.oauth)){let h=s.oauth;u={clientId:C(h.client_id)??C(h.clientId),resource:C(h.resource),scopes:Q(h.scopes)}}return{name:r,filePath:e,type:l,enabled:Ie(s.enabled,!0),description:C(s.description)??(n.trim()||void 0),source:C(s.source)==="imported"?"imported":"manual",command:C(s.command),args:Q(s.args),env:Na(s.env),envSecretKeys:Q(s.env_secret_keys),url:C(s.url),headers:Na(s.headers),auth:d,oauth:u,status:"disconnected",scope:"user",tools:[],toolDetails:[]}}mcpServerFrontmatter(e){let t={name:e.name,transport:e.type,enabled:e.enabled};return e.source&&(t.source=e.source),e.type==="stdio"?(e.command&&(t.command=e.command),e.args&&e.args.length>0&&(t.args=e.args),e.env&&Object.keys(e.env).length>0&&(t.env=e.env),e.envSecretKeys&&e.envSecretKeys.length>0&&(t.env_secret_keys=e.envSecretKeys)):(e.url&&(t.url=e.url),e.headers&&Object.keys(e.headers).length>0&&(t.headers=e.headers),e.auth&&(t.auth=e.auth),e.oauth&&(e.oauth.clientId||e.oauth.resource||(e.oauth.scopes?.length??0)>0)&&(t.oauth={client_id:e.oauth.clientId||void 0,resource:e.oauth.resource||void 0,scopes:e.oauth.scopes&&e.oauth.scopes.length>0?e.oauth.scopes:void 0})),t}async saveMcpServer(e,t=""){let s=this.mcpServerFrontmatter(e),n=U(s,t.trim()),r=e.filePath?this.vault.getAbstractFileByPath(e.filePath):null;if(r instanceof Wa.TFile)return await this.vault.modify(r,n),r.path;let i=await _t(this.vault,this.deps.getMcpDir(),z(e.name));return await fe(this.vault,this.deps.getMcpDir()),await this.vault.create(i,n),i}async setMcpServerEnabled(e,t){let s=this.deps.getServerByName(e);if(!s?.filePath)return;let n=this.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof Wa.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);i.enabled=t,await this.vault.modify(n,U(i,o))}async deleteMcpServer(e){let t=this.deps.getServerByName(e);t?.filePath&&await qe(this.app,t.filePath)}};var dt=require("obsidian");var En=class{constructor(e,t){this.app=e;this.deps=t;this.vault=e.vault}vault;getProposalsDir(){return(0,dt.normalizePath)(`${this.deps.getFleetRoot()}/proposals`)}async listProposals(){let e=this.vault.getAbstractFileByPath(this.getProposalsDir());if(!(e instanceof dt.TFolder))return[];let t=[];for(let s of e.children){if(!(s instanceof dt.TFile)||s.extension!=="md")continue;let n=await this.readProposal(s.basename);n&&t.push(n)}return t.sort((s,n)=>n.created.localeCompare(s.created)),t}async readProposal(e){let t=(0,dt.normalizePath)(`${this.getProposalsDir()}/${e}.md`),s=this.vault.getAbstractFileByPath(t);if(!(s instanceof dt.TFile))return null;let{frontmatter:n,body:r}=W(await this.vault.cachedRead(s)),i=n.type==="skill_modify"?"skill_modify":"skill_create",o=n.status==="accepted"||n.status==="rejected"?n.status:"pending";return{id:e,type:i,agent:C(n.agent)??"",status:o,created:C(n.created)??"",targetSkill:C(n.target_skill),candidate:C(n.candidate),evidence:Q(n.evidence),rationale:C(n.rationale)??"",body:r}}async writeProposal(e){await fe(this.vault,this.getProposalsDir());let t=(0,dt.normalizePath)(`${this.getProposalsDir()}/${e.id}.md`),s={id:e.id,type:e.type,agent:e.agent,status:e.status,created:e.created,target_skill:e.targetSkill||void 0,candidate:e.candidate||void 0,evidence:e.evidence.length?e.evidence:void 0,rationale:e.rationale||void 0},n=U(s,e.body||""),r=this.vault.getAbstractFileByPath(t);r instanceof dt.TFile?await this.vault.modify(r,n):await We(this.vault,t,n)}async setProposalStatus(e,t){let s=await this.readProposal(e);s&&(s.status=t,await this.writeProposal(s))}async applyProposal(e){if(e.type==="skill_create"){let t=e.targetSkill||`learned-${z(e.rationale).slice(0,24)||"skill"}`,s=await _t(this.vault,this.deps.getSkillsDir(),z(t)),r={name:s.split("/").pop()?.replace(/\.md$/,"")||z(t),description:e.rationale||`Auto-proposed from recurring pattern for ${e.agent}.`,tags:["proposed"]};return await this.vault.create(s,U(r,e.body||"Skill instructions go here.")),s}if(e.targetSkill){let t=this.deps.getSkillByName(e.targetSkill);if(t){let s=this.vault.getAbstractFileByPath(t.filePath);if(s instanceof dt.TFile){let n=await this.vault.cachedRead(s),r=`
|
|
11702
|
+
|
|
11703
|
+
## Proposed update (${new Date().toISOString().slice(0,10)})
|
|
11704
|
+
${e.body}`;return await this.vault.modify(s,`${n.trimEnd()}${r}
|
|
11705
|
+
`),t.filePath}}}return null}async deleteProposal(e){await qe(this.app,(0,dt.normalizePath)(`${this.getProposalsDir()}/${e}.md`))}};var bt=require("obsidian");var Pt=require("child_process"),Si=require("fs"),Rn=require("os"),Xt=require("path");function qa(){return(0,Rn.homedir)()}function Ci(){if(process.platform==="darwin")return"/bin/zsh";for(let a of["/bin/bash","/bin/zsh","/bin/sh"])if((0,Si.existsSync)(a))return a;return"/bin/sh"}function ed(a){return`'${a.replace(/'/g,"'\\''")}'`}function wt(a,e,t){let s={cwd:t?.cwd,env:t?.env};if(process.platform==="win32")return(0,Pt.spawn)(a,e,s);let n=Ci(),r=[a,...e].map(ed).join(" ");return(0,Pt.spawn)(n,["-l","-c",r],s)}function Ti(a,e){let t={cwd:e?.cwd,env:e?.env,stdio:["pipe","pipe","pipe"]};if(process.platform==="win32")return(0,Pt.spawn)(a,[],{...t,shell:!0});let s=Ci();return(0,Pt.spawn)(s,["-l","-c",a],t)}function _i(a){try{require("electron").shell.openExternal(a)}catch{switch(process.platform){case"darwin":(0,Pt.spawn)("open",[a],{stdio:"ignore"});break;case"win32":(0,Pt.spawn)("cmd.exe",["/c","start","",a.replace(/&/g,"^&")],{stdio:"ignore"});break;default:(0,Pt.spawn)("xdg-open",[a],{stdio:"ignore"});break}}}function re(a){return a.split(/\r?\n/)}function Ai(a){let e=(0,Rn.homedir)();if(process.platform==="win32")return[a,(0,Xt.join)(process.env.APPDATA??"","Claude","claude.exe"),(0,Xt.join)(process.env.LOCALAPPDATA??"","Claude","claude.exe"),(0,Xt.join)(e,".local","bin","claude.exe"),"claude.exe","claude"].filter(s=>!!s&&Dn(s));let t=[a,(0,Xt.join)(e,".local","bin","claude")];return process.platform==="darwin"&&t.push("/opt/homebrew/bin/claude"),t.push("/usr/local/bin/claude","/usr/bin/claude","claude"),t.filter(s=>!!s&&Dn(s))}function za(a){let e=(0,Rn.homedir)();if(process.platform==="win32")return[a,(0,Xt.join)(e,".local","bin","codex.exe"),"codex.exe","codex"].filter(s=>!!s&&Dn(s));let t=[a,(0,Xt.join)(e,".local","bin","codex")];return process.platform==="darwin"&&t.push("/opt/homebrew/bin/codex"),t.push("/usr/local/bin/codex","/usr/bin/codex","codex"),t.filter(s=>!!s&&Dn(s))}function Dn(a){return!a||/[\n\r\0]/.test(a)?!1:a.startsWith("/")?/^[\w/.@+-]+$/.test(a):a.startsWith("~")?/^~[\w/.@+-]*$/.test(a):/^[a-zA-Z]:[\\/]/.test(a)?/^[a-zA-Z]:[\\/][\w\\/. @+-]+$/.test(a):a.startsWith("\\\\")?/^\\\\[\w\\/. @+-]+$/.test(a):!a.includes("/")&&!a.includes("\\")?/^[\w.@+-]+$/.test(a):!1}function Ga(a){return!!(a.includes("/")||a.includes("\\"))}var In=class{constructor(e,t){this.getRunsRoot=t;this.vault=e.vault}runLogCache=new Map;vault;async listRecentRuns(e=50){let t=this.vault.getAbstractFileByPath(this.getRunsRoot());if(!(t instanceof bt.TFolder))return[];let s=[];ps(t,s),s.sort((i,o)=>o.path.localeCompare(i.path));let n=s.slice(0,e),r=[];for(let i of n){let o=await this.readRunLog(i);o&&r.push(o)}return r.sort((i,o)=>o.started.localeCompare(i.started))}async listRunsSince(e){let t=this.vault.getAbstractFileByPath(this.getRunsRoot());if(!(t instanceof bt.TFolder))return[];let s=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,n=[];for(let i of t.children)i instanceof bt.TFolder&&(i.name<s||ps(i,n));let r=[];for(let i of n){let o=await this.readRunLog(i);o&&r.push(o)}return r.sort((i,o)=>o.started.localeCompare(i.started))}async readRunLog(e){let t=this.runLogCache.get(e.path);if(t&&t.mtime===e.stat.mtime&&t.size===e.stat.size)return t.run;let s=await this.vault.cachedRead(e),{frontmatter:n,body:r}=W(s),i=r.match(/## Prompt\n([\s\S]*?)(?:\n## Result\n|\n## Output\n|$)/),o=r.match(/## Result\n([\s\S]*?)(?:\n## Output\n|$)/),l=r.match(/## Output\n([\s\S]*?)(?:\n## Tools Used\n|$)/),c=r.match(/## Tools Used\n([\s\S]*?)(?:\n## STDERR\n|$)/),d={filePath:e.path,runId:C(n.run_id)??e.basename,agent:C(n.agent)??"unknown",task:C(n.task)??"unknown",status:C(n.status)??"failure",started:C(n.started)??new Date(e.stat.ctime).toISOString(),completed:C(n.completed),durationSeconds:Pe(n.duration_seconds,0),tokensUsed:typeof n.tokens_used=="number"?n.tokens_used:void 0,costUsd:typeof n.cost_usd=="number"?n.cost_usd:void 0,model:C(n.model)??ft.defaultModel,modelSource:(()=>{let u=C(n.model_source);if(u==="task"||u==="agent"||u==="settings"||u==="cli-default")return u})(),concreteModel:C(n.resolved_concrete_model),exitCode:typeof n.exit_code=="number"?n.exit_code:null,tags:Q(n.tags),prompt:i?.[1]?.trim()??"",output:l?.[1]?.trim()??"",finalResult:o?.[1]?.trim()||void 0,toolsUsed:c?.[1]?re(c[1]).map(u=>u.replace(/^- /,"").trim()).filter(Boolean):[],approvals:this.parseApprovals(n.approvals)};return this.runLogCache.size>=5e3&&this.runLogCache.clear(),this.runLogCache.set(e.path,{mtime:e.stat.mtime,size:e.stat.size,run:d}),d}async writeRunLog(e){let t=new Date(e.started),s=(0,bt.normalizePath)(`${this.getRunsRoot()}/${t.toISOString().slice(0,10)}`);await fe(this.vault,s);let n=`${t.toISOString().slice(11,19).replace(/:/g,"")}-${z(e.agent)}-${z(e.task)}.md`,r=(0,bt.normalizePath)(`${s}/${n}`),i=U({run_id:e.runId,agent:e.agent,task:e.task,status:e.status,started:e.started,completed:e.completed,duration_seconds:e.durationSeconds,tokens_used:e.tokensUsed,cost_usd:e.costUsd,model:e.model,model_source:e.modelSource,resolved_concrete_model:e.concreteModel,exit_code:e.exitCode,tags:e.tags,approvals:e.approvals},["## Prompt","",e.prompt.trim(),"",...e.finalResult&&e.finalResult.trim()?["## Result","",e.finalResult.trim(),""]:[],"## Output","",e.output.trim()||"(no output)","","## Tools Used","",...e.toolsUsed.length>0?e.toolsUsed.map(l=>`- ${l}`):["- none"],...e.stderr?["","## STDERR","",e.stderr.trim()]:[]].join(`
|
|
11706
|
+
`)),o=this.vault.getAbstractFileByPath(r);return o instanceof bt.TFile?await this.vault.modify(o,i):await this.vault.create(r,i),r}async setApprovalDecision(e,t,s){let n=this.vault.getAbstractFileByPath(e);if(!(n instanceof bt.TFile))return;let r=await this.vault.cachedRead(n),{frontmatter:i,body:o}=W(r),l=(this.parseApprovals(i.approvals)??[]).map(c=>c.tool===t?{...c,status:s,resolvedAt:new Date().toISOString()}:c);await this.vault.modify(n,U({...i,approvals:l},o))}parseApprovals(e){if(Array.isArray(e))return e.flatMap(t=>{if(!Tt(t)||!C(t.tool))return[];let s=C(t.tool);return s?[{tool:s,command:C(t.command),reason:C(t.reason),status:C(t.status)??"pending",resolvedAt:C(t.resolvedAt),note:C(t.note)}]:[]})}};var Va=require("obsidian");function Pi(a){let e=new Map;for(let s of a){if(typeof s.costUsd!="number")continue;let n=e.get(s.agent);n?n.push(s):e.set(s.agent,[s])}let t=0;for(let s of e.values()){s.sort((r,i)=>r.ts.localeCompare(i.ts));let n=0;for(let r of s){let i=r.costUsd,o=i>=n?i-n:i;n=i,o!==i&&t++,r.costUsd=o}}return t}var Mn=class{constructor(e,t){this.getUsageDir=t;this.vault=e.vault}vault;usageLedgerPath(e){return(0,Va.normalizePath)(`${this.getUsageDir()}/${e.slice(0,10)}.jsonl`)}async appendUsage(e){await fe(this.vault,this.getUsageDir());let t=this.usageLedgerPath(e.ts),s=`${JSON.stringify(e)}
|
|
11707
|
+
`,n=this.vault.adapter;await n.exists(t)?await n.append(t,s):await n.write(t,s)}async readUsageSince(e){let t=this.getUsageDir(),s=this.vault.adapter;if(!await s.exists(t))return[];let n=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,r=[],i=await s.list(t);for(let o of i.files){if(!o.endsWith(".jsonl")||(o.split("/").pop()??"").replace(/\.jsonl$/,"")<n)continue;let c;try{c=await s.read(o)}catch{continue}for(let d of c.split(`
|
|
11708
|
+
`)){let u=d.trim();if(u)try{r.push(JSON.parse(u))}catch(h){console.warn(`Agent Fleet: skipping corrupt usage record in ${o}`,h)}}}return r}async migrateUsageLedgerCosts(){let e=this.getUsageDir(),t=this.vault.adapter;if(!await t.exists(e))return null;let s=(0,Va.normalizePath)(`${e}/.cost-delta-v1`);if(await t.exists(s))return null;try{let n=await t.list(e),r=[],i=[];for(let l of n.files){if(!l.endsWith(".jsonl"))continue;let c;try{c=await t.read(l)}catch{continue}let d=[];for(let u of c.split(`
|
|
11709
|
+
`)){let h=u.trim();if(h)try{d.push(JSON.parse(h))}catch(p){console.warn(`Agent Fleet: skipping corrupt usage record in ${l} during cost migration`,p)}}r.push({path:l,records:d}),i.push(...d)}let o=Pi(i);if(o>0)for(let{path:l,records:c}of r){if(c.length===0)continue;let d=c.map(u=>JSON.stringify(u)).join(`
|
|
11710
|
+
`)+`
|
|
11711
|
+
`;await t.write(l,d)}return await t.write(s,`migrated ${i.length} rows; corrected ${o}
|
|
11712
|
+
`),{files:r.length,rows:i.length,changed:o}}catch(n){return console.error("Agent Fleet: usage-ledger cost migration failed (ledger left untouched)",n),null}}};function Ei(a){let e=0;for(let t=0;t<a.length;t++){let s=a.charCodeAt(t);e=(e<<5)-e+s|0}return e.toString(36)}var Us=class{constructor(e,t){this.app=e;this.settings=t;this.vault=e.vault,this.entities=new Cn(e,{settings:t,getFleetRoot:()=>this.getFleetRoot(),getSubfolder:s=>this.getSubfolder(s),parseMcpServerFile:(s,n)=>this.mcp.parseMcpServerFile(s,n)}),this.mutations=new Sn(e,{store:this.entities,getSubfolder:s=>this.getSubfolder(s),getMemoryPath:s=>this.getMemoryPath(s),getMemoryDir:s=>this.getMemoryDir(s)}),this.runLogs=new In(e,()=>this.getRunsRoot()),this.usage=new Mn(e,()=>this.getSubfolder("usage")),this.memory=new An(e,()=>this.getSubfolder("memory")),this.conversations=new xn(e,s=>this.getMemoryPath(s)),this.proposals=new En(e,{getFleetRoot:()=>this.getFleetRoot(),getSkillsDir:()=>this.getSubfolder("skills"),getSkillByName:s=>this.getSkillByName(s)}),this.mcp=new Pn(e,{getMcpDir:()=>this.getSubfolder("mcp"),getServerByName:s=>this.getMcpServerByName(s),reportIssue:(s,n)=>this.entities.setIssue(s,n)})}vault;entities;mutations;runLogs;usage;conversations;proposals;mcp;memory;setChannelCredentialGetter(e){this.entities.setChannelCredentialGetter(e)}getVaultBasePath(){let e=this.vault.adapter;return e instanceof Et.FileSystemAdapter?e.getBasePath():void 0}getFleetRoot(){return(0,Et.normalizePath)(this.settings.fleetFolder)}getSubfolder(e){return(0,Et.normalizePath)(`${this.getFleetRoot()}/${e}`)}async ensureFleetStructure(){let e=this.getFleetRoot(),t=!this.vault.getAbstractFileByPath(e);await fe(this.vault,e);for(let s of Xr)await fe(this.vault,this.getSubfolder(s));return t}async ensureSamples(){let e=this.getFleetRoot();for(let t of Ls){let s=(0,Et.normalizePath)(`${e}/${t.path}`),n=s.substring(0,s.lastIndexOf("/"));await fe(this.vault,n),await We(this.vault,s,t.content)}}async updateDefaults(e){let t=this.getFleetRoot(),s={...e};for(let n of Ls){let r=(0,Et.normalizePath)(`${t}/${n.path}`),i=Ei(n.content),o=e[n.path];if(o===i)continue;let l=this.vault.getAbstractFileByPath(r);if(!(l instanceof Et.TFile)){let u=r.substring(0,r.lastIndexOf("/"));await fe(this.vault,u),await We(this.vault,r,n.content),s[n.path]=i;continue}let c=await this.vault.cachedRead(l),d=Ei(c);(!o||d===o)&&(await this.vault.modify(l,n.content),s[n.path]=i)}return s}async loadAll(){return this.entities.loadAll()}async loadFile(e){return this.entities.loadFile(e)}removeFile(e){this.entities.removeFile(e)}getSnapshot(){return this.entities.getSnapshot()}getAgentByName(e){return this.entities.getAgentByName(e)}getSkillByName(e){return this.entities.getSkillByName(e)}getTaskById(e){return this.entities.getTaskById(e)}getTasksForAgent(e){return this.entities.getTasksForAgent(e)}getChannelByName(e){return this.entities.getChannelByName(e)}getChannelsForAgent(e){return this.entities.getChannelsForAgent(e)}getMcpServers(){return this.entities.getMcpServers()}getMcpServerByName(e){return this.entities.getMcpServerByName(e)}getRunsRoot(){return this.getSubfolder("runs")}getMemoryPath(e){return this.memory.getMemoryPath(e)}getMemoryDir(e){return this.memory.getMemoryDir(e)}getWorkingMemoryPath(e){return this.memory.getWorkingMemoryPath(e)}getRawMemoryPath(e,t){return this.memory.getRawMemoryPath(e,t)}async readWorkingMemory(e){return this.memory.readWorkingMemory(e)}async writeWorkingMemory(e,t){return this.memory.writeWorkingMemory(e,t)}async migrateLegacyMemory(e){return this.memory.migrateLegacyMemory(e)}async migrateAllLegacyMemory(){for(let e of this.getSnapshot().agents)if(e.memory)try{await this.memory.migrateLegacyMemory(e.name)}catch(t){console.warn(`Agent Fleet: legacy memory migration failed for "${e.name}"`,t)}}getPendingDir(e){return this.memory.getPendingDir(e)}getPendingDirAbsolutePath(e){return this.memory.getPendingDirAbsolutePath(e)}async ensureMemoryDir(e){return this.memory.ensureMemoryDir(e)}async readAndClearPending(e){return this.memory.readAndClearPending(e)}async readRecentRaw(e,t=2){return this.memory.readRecentRaw(e,t)}getCandidatesPath(e){return this.memory.getCandidatesPath(e)}async readCandidates(e){return this.memory.readCandidates(e)}async writeCandidates(e,t){return this.memory.writeCandidates(e,t)}getProposalsDir(){return this.proposals.getProposalsDir()}async listProposals(){return this.proposals.listProposals()}async readProposal(e){return this.proposals.readProposal(e)}async writeProposal(e){return this.proposals.writeProposal(e)}async setProposalStatus(e,t){return this.proposals.setProposalStatus(e,t)}async applyProposal(e){return this.proposals.applyProposal(e)}async deleteProposal(e){return this.proposals.deleteProposal(e)}async appendRawMemory(e,t,s){return this.memory.appendRawMemory(e,t,s)}async listConversations(e){return this.conversations.listConversations(e)}async createConversation(e,t,s){return this.conversations.createConversation(e,t,s)}async renameConversation(e,t,s){return this.conversations.renameConversation(e,t,s)}async deleteConversation(e,t){return this.conversations.deleteConversation(e,t)}async getMemory(e){return this.memory.getMemory(e)}async appendMemory(e,t){return this.memory.appendMemory(e,t)}async listRecentRuns(e=50){return this.runLogs.listRecentRuns(e)}async listRunsSince(e){return this.runLogs.listRunsSince(e)}async appendUsage(e){return this.usage.appendUsage(e)}async readUsageSince(e){return this.usage.readUsageSince(e)}async migrateUsageLedgerCosts(){return this.usage.migrateUsageLedgerCosts()}async readRunLog(e){return this.runLogs.readRunLog(e)}async writeRunLog(e){return this.runLogs.writeRunLog(e)}async setApprovalDecision(e,t,s){return this.runLogs.setApprovalDecision(e,t,s)}async updateTaskRunMetadata(e,t){return this.mutations.updateTaskRunMetadata(e,t)}async createAgentTemplate(e){return this.mutations.createAgentTemplate(e)}async createAgentFolder(e){return this.mutations.createAgentFolder(e)}async createSkillTemplate(e){return this.mutations.createSkillTemplate(e)}async createSkillFolder(e){return this.mutations.createSkillFolder(e)}async updateAgent(e,t){return this.mutations.updateAgent(e,t)}async updateTask(e,t){return this.mutations.updateTask(e,t)}async updateSkill(e,t){return this.mutations.updateSkill(e,t)}async deleteSkill(e){return this.mutations.deleteSkill(e)}async deleteTask(e){return this.mutations.deleteTask(e)}async updateChannel(e,t){return this.mutations.updateChannel(e,t)}async deleteChannel(e){return this.mutations.deleteChannel(e)}async updateHeartbeat(e,t){return this.mutations.updateHeartbeat(e,t)}async deleteAgent(e,t){return this.mutations.deleteAgent(e,t)}async saveMcpServer(e,t=""){return this.mcp.saveMcpServer(e,t)}async setMcpServerEnabled(e,t){return this.mcp.setMcpServerEnabled(e,t)}async deleteMcpServer(e){return this.mcp.deleteMcpServer(e)}async trashFile(e){await qe(this.app,e)}async getAvailablePath(e,t){return _t(this.vault,e,t)}};var Qt=require("obsidian"),Fn=class extends Qt.Modal{constructor(t,s,n){super(t);this.info=s;this.onConfirm=n}deleteTasks=!0;onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("af-confirm-delete-modal");let s=t.createDiv({cls:"af-delete-header"}),n=s.createSpan({cls:"af-delete-header-icon"});(0,Qt.setIcon)(n,"alert-triangle"),s.createEl("h3",{text:`Delete agent "${this.info.agentName}"?`});let r=t.createDiv({cls:"af-delete-summary"});r.createDiv({text:"This action will:"});let i=r.createEl("ul",{cls:"af-delete-impact-list"});i.createEl("li",{text:"Move the agent definition to trash"}),this.info.hasMemory&&i.createEl("li",{text:"Move the agent's memory file to trash"}),this.info.taskCount>0&&i.createEl("li").setText(`${this.info.taskCount} task${this.info.taskCount!==1?"s":""} reference this agent`),this.info.runCount>0&&i.createEl("li",{cls:"af-delete-preserved"}).setText(`${this.info.runCount} run log${this.info.runCount!==1?"s":""} will be preserved`),t.createDiv({cls:"af-delete-note",text:"Files are moved to your system trash and can be recovered."}),this.info.taskCount>0&&new Qt.Setting(t).setName("Also delete associated tasks").setDesc(`Delete ${this.info.taskCount} task${this.info.taskCount!==1?"s":""} that reference this agent`).addToggle(u=>{u.setValue(this.deleteTasks),u.onChange(h=>{this.deleteTasks=h})});let o=t.createDiv({cls:"af-delete-actions"}),l=o.createEl("button",{text:"Cancel"});l.onclick=()=>this.close();let c=o.createEl("button",{cls:"af-delete-confirm-btn",text:"Delete Agent"}),d=c.createSpan({cls:"af-delete-btn-icon"});(0,Qt.setIcon)(d,"trash-2"),c.onclick=()=>{this.onConfirm(this.deleteTasks),this.close()}}};var D=require("obsidian");var Ln=require("obsidian"),ut=class extends Ln.Modal{constructor(t,s){super(t);this.opts=s}onOpen(){let{contentEl:t}=this;t.empty(),t.createEl("h3",{text:this.opts.title});for(let s of this.opts.body.split(`
|
|
11713
|
+
|
|
11714
|
+
`))s.trim()&&t.createEl("p",{text:s});new Ln.Setting(t).addButton(s=>s.setButtonText("Cancel").onClick(()=>this.close())).addButton(s=>{s.setButtonText(this.opts.confirmText??"Confirm").onClick(()=>{this.close(),this.opts.onConfirm()}),this.opts.danger&&s.setWarning()})}onClose(){this.contentEl.empty()}};var Nn=[{value:"opus",label:"opus \u2014 latest Opus"},{value:"sonnet",label:"sonnet \u2014 latest Sonnet"},{value:"haiku",label:"haiku \u2014 latest Haiku"},{value:"opusplan",label:"opusplan \u2014 plan-mode Opus"}],Bn=[{value:"gpt-5.5",label:"gpt-5.5 \u2014 frontier"},{value:"gpt-5.4",label:"gpt-5.4"},{value:"gpt-5.4-mini",label:"gpt-5.4-mini \u2014 fast"},{value:"gpt-5.3-codex",label:"gpt-5.3-codex"}],On="__custom__";function Di(a){let e=(a??"").trim().toLowerCase();return e==="codex"||e==="openai-codex"}function Ri(a){return Di(a)?Bn:Nn}function td(a,e){let t=a.trim();return!t||t==="default"||t==="subscription"?"inherit":Ri(e).some(s=>s.value===t)?"alias":"custom"}function Nt(a,e){a.empty(),a.addClass("af-model-picker");let t=Di(e.adapter),s=Ri(e.adapter),n=td(e.value,e.adapter),r=a.createEl("select",{cls:"af-form-select af-mp-select"}),i=e.allowInherit?e.inheritPlaceholder??"Inherit from agent":t?"Default (let Codex pick)":"Default (let Claude Code pick)";r.createEl("option",{text:i,attr:{value:""}});let o=r.createEl("optgroup",{attr:{label:t?"Codex models":"Aliases (any backend)"}});for(let c of s)o.createEl("option",{text:c.label,attr:{value:c.value}});r.createEl("option",{text:"Custom\u2026",attr:{value:On}});let l=a.createEl("input",{cls:"af-form-input af-mp-custom-input",attr:{type:"text",placeholder:t?"e.g. gpt-5.5 \xB7 gpt-5.4-mini":"e.g. claude-opus-4-7 \xB7 us.anthropic.claude-opus-4-7 \xB7 claude-opus-4-7@20251101",spellcheck:"false"}});n==="inherit"?(r.value="",l.value="",l.setCssStyles({display:"none"})):n==="alias"?(r.value=e.value.trim(),l.value="",l.setCssStyles({display:"none"})):(r.value=On,l.value=e.value.trim(),l.setCssStyles({display:""})),r.addEventListener("change",()=>{r.value===On?(l.setCssStyles({display:""}),l.focus(),e.onChange(l.value.trim())):(l.setCssStyles({display:"none"}),e.onChange(r.value))}),l.addEventListener("input",()=>{r.value===On&&e.onChange(l.value.trim())})}var le=require("obsidian");function sd(){let a=new Date,e=a.getFullYear(),t=String(a.getMonth()+1).padStart(2,"0"),s=String(a.getDate()).padStart(2,"0");return`${e}-${t}-${s}`}var nd="0 3 * * *",ad="0 9 * * 0";function Ya(){return{scopeSlug:"",scopeRoot:"",inboxPath:"_sources/inbox",archivePath:"_sources/archive",topicsRoot:"_topics",indexPath:"index.md",logPath:"log.md",watchedFolders:[],excludePatterns:[],watchedSince:sd(),heartbeatChannel:"",fileSubstantiveAnswers:!0,obsidianUrlScheme:!0,maxTokensPerIngest:6e4,maxTokensPerRefresh:3e4,indexSplitThreshold:100,dedupSimilarityThreshold:.82,summaryStaleDays:30,failedPath:"_sources/failed",stateFile:".wiki-keeper-state.json"}}var Fi=Ya();function Ka(a){let e=z(a).trim();return e?`wiki-keeper-${e}`:"wiki-keeper"}function rd(a,e){let t=e||"the whole vault",s={name:a,description:`Cultivates ${t} as a self-maintaining wiki. Ingests new sources, extracts durable claims from watched folders, answers questions with citations, and periodically lints.`,avatar:"library",enabled:!0,skills:["wiki-ingest","wiki-query","wiki-lint","wiki-refresh"],tags:e?["wiki-keeper",`scope:${z(e)}`]:["wiki-keeper"]},n=`You are the Wiki Keeper for the \`${t}\` scope. Maintain it as a persistent, interlinked knowledge base (Karpathy's "LLM wiki" pattern).
|
|
11714
11715
|
|
|
11715
11716
|
## Scope isolation
|
|
11716
11717
|
|
|
@@ -11752,7 +11753,7 @@ Use \`memory\` for procedural learning ("user prefers concept pages under sub-fo
|
|
|
11752
11753
|
- Never write outside the scope root.
|
|
11753
11754
|
- Never edit \`## Claims\` history (append only).
|
|
11754
11755
|
- Never edit \`## Summary\` blocks by hand \u2014 \`wiki-refresh\` owns them.
|
|
11755
|
-
`;return
|
|
11756
|
+
`;return U(s,n)}function id(a){let e={model:"opus",adapter:"claude-code",timeout:900,max_retries:1,cwd:"",permission_mode:"acceptEdits",approval_required:["Write"],memory:!0,memory_max_entries:200,wiki_keeper:{scope_root:a.scopeRoot,inbox_path:a.inboxPath,archive_path:a.archivePath,failed_path:a.failedPath,topics_root:a.topicsRoot,index_path:a.indexPath,log_path:a.logPath,watched_folders:a.watchedFolders,exclude_patterns:a.excludePatterns,watched_since:a.watchedSince,file_substantive_answers:a.fileSubstantiveAnswers,obsidian_url_scheme:a.obsidianUrlScheme,max_tokens_per_ingest:a.maxTokensPerIngest,max_tokens_per_refresh:a.maxTokensPerRefresh,index_split_threshold:a.indexSplitThreshold,dedup_similarity_threshold:a.dedupSimilarityThreshold,summary_stale_days:a.summaryStaleDays,state_file:a.stateFile}};return U(e,"")}function od(a){let e={enabled:!0,schedule:nd,notify:!0};return a.heartbeatChannel&&(e.channel=a.heartbeatChannel),U(e,`Run wiki-ingest in both modes:
|
|
11756
11757
|
|
|
11757
11758
|
1. Drain every unprocessed file in the configured inbox (inbox mode).
|
|
11758
11759
|
2. Diff watched folders against the state file; process changed or new files (watched mode).
|
|
@@ -11760,37 +11761,46 @@ Use \`memory\` for procedural learning ("user prefers concept pages under sub-fo
|
|
|
11760
11761
|
Lint runs on its own schedule via the sibling \`*-lint\` task.
|
|
11761
11762
|
|
|
11762
11763
|
Change the schedule by editing this file's \`schedule:\` frontmatter directly, or via the agent editor in the dashboard.
|
|
11763
|
-
`)}function
|
|
11764
|
-
`;return s instanceof
|
|
11764
|
+
`)}function Li(a){let t={task_id:`${a}-lint`,agent:a,type:"recurring",schedule:ad,priority:"low",enabled:!0,created:new Date().toISOString(),run_count:0,catch_up:!1,tags:["wiki-keeper","lint"]};return U(t,"Run the `wiki-lint` skill on the current scope.\n\nWrite the report as a new `## Lint YYYY-MM-DD` section inside the fenced block in log.md.\n")}function Ja(a,e){return(0,le.normalizePath)(`${a}/tasks/${e}-lint.md`)}var ld="# Wiki Schema\n\n## Page types\n\n- **Entity pages** \u2014 people, orgs, products. Frontmatter: `type: entity`.\n- **Concept pages** \u2014 ideas, techniques, patterns. `type: concept`.\n- **Event pages** \u2014 meetings, releases, decisions. `type: event, date: YYYY-MM-DD`.\n- **Summary pages** (inbox-mode only) \u2014 one per ingested inbox source. `type: summary, source: <filename>`.\n- **Synthesis pages** \u2014 filed answers from `wiki-query` substantive responses. `type: synthesis, question: <q>, refreshed: <ISO>`. Live under `_topics/syntheses/`.\n\nTopic pages of type entity/concept/event SHOULD also carry:\n- `summary_refreshed: <ISO>` \u2014 last time `wiki-refresh` regenerated this page's summary block. Empty string on creation.\n- `claims_at_refresh: <int>` \u2014 how many claims existed at last refresh. Drives the staleness threshold.\n\n## Page anatomy\n\nEvery entity/concept/event page has this structure:\n\n```markdown\n---\ntype: entity\nname: Vendor X\nsummary_refreshed: 2026-04-26\nclaims_at_refresh: 14\n---\n\n<!-- wiki-keeper:summary:begin -->\n## Summary\n\n- 3-7 bullet synthesis maintained by wiki-refresh.\n- Forward-links to other topics with [[wikilinks]].\n<!-- wiki-keeper:summary:end -->\n\n## Claims\n\n- 2026-04-18 [meeting]: from [[meetings/2026-04-18-vendor-sync|vendor-sync]]: Vendor X raised prices 15%\n- 2026-04-12 [doc]: from [[summaries/2026-04-12-renewal-brief|renewal-brief]]: contract auto-renews 2026-12-01\n\n## Contradictions\n\n(only present when contradictions exist)\n```\n\nThe fenced summary block is auto-managed by `wiki-refresh`. The `## Claims` section is append-only history written by `wiki-ingest` and `wiki-query` compounding. `## Contradictions` is created on demand. **Anything outside these structures is user-authored** and must be preserved.\n\n## Source-type tags\n\nEvery dated bullet in `## Claims` carries a tag indicating the source type:\n\n- `[doc]` \u2014 PDF, DOCX, XLSX, or other document\n- `[meeting]` \u2014 meeting note or transcript\n- `[email]` \u2014 email forward\n- `[note]` \u2014 markdown daily note or in-vault note\n- `[web]` \u2014 web clipping or URL drop\n- `[synthesis]` \u2014 bullet emitted by `wiki-query` compounding (links to a synthesis page)\n- `[other]` \u2014 fallback\n\nTags help `wiki-query` weight evidence quality and help `wiki-lint` identify drift.\n\n## Naming\n\n- Slug-case filenames: `vendor-x.md`, not `Vendor X.md`.\n- Group by type under `_topics/<type>/` when there are >5 pages of a type.\n\n## Links\n\n- Every entity/concept page MUST have \u22651 inbound link from `index.md` (or a sub-MOC) or a sibling.\n- Summary pages MUST forward-link to every entity/concept they mention.\n- Watched-mode extractions append dated entries to topic pages; forward-link to the source file path so readers can find the raw note.\n- Synthesis pages forward-link to every cited topic and earn their place that way (lint exempts them from orphan flagging if they have any outbound links to topics).\n\n## Index split\n\nWhen the topic count exceeds the `index_split_threshold` config value (default 100) or any single type exceeds 30 pages, `index.md` becomes a hub of hubs and per-type sub-MOCs live at `<scope>/index/<type>.md`. After split, new topic-page entries go into the matching sub-MOC, not the root index.\n\n## Conflict resolution\n\n- New claim contradicts existing? Add a `## Contradictions` section with a dated entry. Do NOT overwrite.\n- Flag in `log.md` for user review.\n- `wiki-refresh` reflects unresolved contradictions in the summary so query-time readers see them.\n\n## Failed sources\n\nFiles that fail ingest 3 times in a row are quarantined to `<failed_path>/` (default `_sources/failed/`) with a sidecar `.error.md`. Lint surfaces the quarantine count weekly.\n",cd=["Read","Write","Edit","Glob","Grep","Bash(mv *)","Bash(mkdir *)"],dd=["Bash(rm -rf *)","Bash(git push *)","Bash(rm -rf /*)","Bash(mv * /*)","Bash(cp -r * /*)"];async function Oi(a,e){let t=(0,le.normalizePath)(`${e}/permissions.json`),s=a.getAbstractFileByPath(t),n={allow:[],deny:[]};if(s instanceof le.TFile)try{let o=await a.cachedRead(s),l=JSON.parse(o),c=Array.isArray(l.allow)?l.allow.filter(u=>typeof u=="string"):[],d=Array.isArray(l.deny)?l.deny.filter(u=>typeof u=="string"):[];n={allow:c,deny:d}}catch{}let r={allow:Ii(n.allow,cd),deny:Ii(n.deny,dd)},i=JSON.stringify(r,null,2)+`
|
|
11765
|
+
`;return s instanceof le.TFile?await a.modify(s,i):await a.create(t,i),r}function Ii(a,e){let t=new Set,s=[];for(let n of a)t.has(n)||(t.add(n),s.push(n));for(let n of e)t.has(n)||(t.add(n),s.push(n));return s}async function Ni(a,e,t){let s=Ka(t.scopeSlug||t.scopeRoot),n=(0,le.normalizePath)(`${e}/agents/${s}`);if(await ms(a,n),a.getAbstractFileByPath((0,le.normalizePath)(`${n}/agent.md`)))throw new Error(`Wiki Keeper agent already exists at ${n}. Delete it first or choose a different scope slug.`);await a.create((0,le.normalizePath)(`${n}/agent.md`),rd(s,t.scopeRoot)),await a.create((0,le.normalizePath)(`${n}/config.md`),id(t)),await a.create((0,le.normalizePath)(`${n}/HEARTBEAT.md`),od(t)),await a.create((0,le.normalizePath)(`${n}/CONTEXT.md`),ld),await Oi(a,n);let i=Ja(e,s);a.getAbstractFileByPath(i)||(await ms(a,(0,le.normalizePath)(`${e}/tasks`)),await a.create(i,Li(s)));let o=t.scopeRoot.trim(),l=o?`${o}/`:"";return await ms(a,(0,le.normalizePath)(`${l}${t.inboxPath}`)),await ms(a,(0,le.normalizePath)(`${l}${t.topicsRoot}`)),await Mi(a,(0,le.normalizePath)(`${l}${t.indexPath}`),`# Index
|
|
11765
11766
|
|
|
11766
11767
|
<!-- wiki-keeper:begin -->
|
|
11767
11768
|
<!-- wiki-keeper:end -->
|
|
11768
|
-
`),await
|
|
11769
|
+
`),await Mi(a,(0,le.normalizePath)(`${l}${t.logPath}`),`# Log
|
|
11769
11770
|
|
|
11770
11771
|
<!-- wiki-keeper:begin -->
|
|
11771
11772
|
<!-- wiki-keeper:end -->
|
|
11772
|
-
`),{path:n,name:s}}async function zt(r,t){if(r.getAbstractFileByPath(t))return;let e=t.split("/"),s="";for(let n of e)if(s=s?`${s}/${n}`:n,!r.getAbstractFileByPath(s))try{await r.createFolder(s)}catch(a){if(!(a instanceof Error?a.message:String(a)).includes("already exists"))throw a}}async function Nr(r,t,e){if(r.getAbstractFileByPath(t))return;let s=t.replace(/\/[^/]+$/,"");s&&s!==t&&await zt(r,s),await r.create(t,e)}async function Wr(r,t,e,s){let n=(0,fe.normalizePath)(`${t}/agents/${e}`),a=(0,fe.normalizePath)(`${n}/config.md`),i=r.getAbstractFileByPath(a);if(!(i instanceof fe.TFile))throw new Error(`Config file not found for ${e} at ${a}`);let o=await r.cachedRead(i),{frontmatter:c,body:l}=J(o),h=c.wiki_keeper??{};h.watched_folders=s.watchedFolders,h.exclude_patterns=s.excludePatterns,s.watchedSince?h.watched_since=s.watchedSince:delete h.watched_since,delete h.ingest_schedule,delete h.lint_schedule,delete h.lint_day,h.file_substantive_answers=s.fileSubstantiveAnswers,h.obsidian_url_scheme=s.obsidianUrlScheme,h.max_tokens_per_ingest=s.maxTokensPerIngest,h.max_tokens_per_refresh=s.maxTokensPerRefresh,h.index_split_threshold=s.indexSplitThreshold,h.dedup_similarity_threshold=s.dedupSimilarityThreshold,h.summary_stale_days=s.summaryStaleDays,(typeof h.failed_path!="string"||!h.failed_path)&&(h.failed_path="_sources/failed"),c.wiki_keeper=h,delete c.allowed_tools,delete c.blocked_tools,await r.modify(i,H(c,l)),await $r(r,n);let d=(0,fe.normalizePath)(`${n}/HEARTBEAT.md`),u=r.getAbstractFileByPath(d);if(u instanceof fe.TFile){let f=await r.cachedRead(u),{frontmatter:g,body:y}=J(f);s.heartbeatChannel?g.channel=s.heartbeatChannel:delete g.channel,await r.modify(u,H(g,y))}let p=ra(t,e);r.getAbstractFileByPath(p)instanceof fe.TFile||(await zt(r,(0,fe.normalizePath)(`${t}/tasks`)),await r.create(p,Ur(e)))}async function Hr(r,t,e){let s=r.vault,n=(0,fe.normalizePath)(`${t}/agents/${e}`),a=s.getAbstractFileByPath(n);if(!a)return;if(!(a instanceof fe.TFolder))throw new Error(`Expected folder at ${n}`);await r.fileManager.trashFile(a);let i=ra(t,e),o=s.getAbstractFileByPath(i);o instanceof fe.TFile&&await r.fileManager.trashFile(o)}var en=class extends F.PluginSettingTab{constructor(e){super(e.app,e);this.plugin=e}display(){let{containerEl:e}=this;e.empty(),new F.Setting(e).setName("Fleet folder").addText(a=>a.setValue(this.plugin.settings.fleetFolder).onChange(async i=>{this.plugin.settings.fleetFolder=i.trim()||it.fleetFolder,await this.plugin.saveSettings()})),new F.Setting(e).setName("Claude CLI path").addText(a=>a.setValue(this.plugin.settings.claudeCliPath).onChange(async i=>{this.plugin.settings.claudeCliPath=i.trim()||it.claudeCliPath,await this.plugin.saveSettings()})),new F.Setting(e).setName("Codex CLI path").setDesc("Used by agents with adapter \u201Ccodex\u201D. Install via `npm i -g @openai/codex` and authenticate with `codex login` in a terminal first.").addText(a=>a.setValue(this.plugin.settings.codexCliPath).onChange(async i=>{this.plugin.settings.codexCliPath=i.trim()||it.codexCliPath,await this.plugin.saveSettings()}));let n=new F.Setting(e).setName("Default model").setDesc("Fallback for agents that don\u2019t set their own. Aliases (opus/sonnet/haiku) work on any backend; use Custom for pinned IDs or Bedrock/Vertex/Foundry.").controlEl.createDiv();Rt(n,{value:this.plugin.settings.defaultModel,onChange:async a=>{this.plugin.settings.defaultModel=a||it.defaultModel,await this.plugin.saveSettings()}}),new F.Setting(e).setName("AWS region").addText(a=>a.setValue(this.plugin.settings.awsRegion).onChange(async i=>{this.plugin.settings.awsRegion=i.trim()||it.awsRegion,await this.plugin.saveSettings()})),new F.Setting(e).setName("Max concurrent runs").addSlider(a=>a.setLimits(1,10,1).setValue(this.plugin.settings.maxConcurrentRuns).setDynamicTooltip().onChange(async i=>{this.plugin.settings.maxConcurrentRuns=i,await this.plugin.saveSettings()})),new F.Setting(e).setName("Run log retention").setDesc("Days to keep run logs before auto-prune.").addSlider(a=>a.setLimits(1,365,1).setValue(this.plugin.settings.runLogRetentionDays).setDynamicTooltip().onChange(async i=>{this.plugin.settings.runLogRetentionDays=i,await this.plugin.saveSettings()})),new F.Setting(e).setName("Catch up missed tasks").addToggle(a=>a.setValue(this.plugin.settings.catchUpMissedTasks).onChange(async i=>{this.plugin.settings.catchUpMissedTasks=i,await this.plugin.saveSettings()})),new F.Setting(e).setName("Notification level").addDropdown(a=>a.addOption("all","All").addOption("failures-only","Failures only").addOption("none","None").setValue(this.plugin.settings.notificationLevel).onChange(async i=>{this.plugin.settings.notificationLevel=i,await this.plugin.saveSettings()})),new F.Setting(e).setName("Status bar").addToggle(a=>a.setValue(this.plugin.settings.showStatusBar).onChange(async i=>{this.plugin.settings.showStatusBar=i,await this.plugin.saveSettings(),this.plugin.refreshStatusBar()})),new F.Setting(e).setName("Chat watchdog timeout (minutes)").setDesc("How long a chat session waits for any output from the Claude CLI before killing the subprocess and surfacing a timeout error. Raise this if your agents run long tools (e.g. large web fetches, builds) and you're seeing spurious 'no response' errors.").addSlider(a=>a.setLimits(1,60,1).setValue(this.plugin.settings.chatWatchdogMinutes).setDynamicTooltip().onChange(async i=>{this.plugin.settings.chatWatchdogMinutes=i,await this.plugin.saveSettings()})),new F.Setting(e).setName("Verify Claude CLI").setDesc("Checks that the configured binary is reachable.").addButton(a=>a.setButtonText("Verify").onClick(async()=>{let i=await this.plugin.verifyClaudeCli();new F.Notice(i?"Claude CLI detected.":"Claude CLI check failed. See console for details.")})),new F.Setting(e).setName("Verify Codex CLI").setDesc("Checks that the configured Codex binary is reachable.").addButton(a=>a.setButtonText("Verify").onClick(async()=>{let i=await this.plugin.verifyCodexCli();new F.Notice(i?"Codex CLI detected.":"Codex CLI check failed. See console for details.")})),this.renderWikiKeepersSection(e),this.renderChannelsSection(e)}renderChannelsSection(e){new F.Setting(e).setName("Channels").setHeading();let s=e.createDiv({cls:"af-settings-warning"});s.setCssStyles({padding:"12px"}),s.setCssStyles({margin:"8px 0 16px 0"}),s.setCssStyles({border:"1px solid var(--background-modifier-border)"}),s.setCssStyles({borderRadius:"6px"}),s.setCssStyles({background:"var(--background-secondary)"}),s.createEl("strong",{text:"Credential storage: "});let n=this.plugin.app.vault.configDir;s.createSpan({text:`Channel credentials are stored in this plugin's data.json inside your vault's ${n} folder. If you sync your ${n} folder across devices, credentials will sync with it. Do not commit this file to a public git repository.`}),new F.Setting(e).setName("Max concurrent channel sessions").setDesc("Hard cap on live claude subprocesses across all channels. Oldest idle session is hibernated when exceeded.").addSlider(d=>d.setLimits(1,20,1).setValue(this.plugin.settings.maxConcurrentChannelSessions).setDynamicTooltip().onChange(async u=>{this.plugin.settings.maxConcurrentChannelSessions=u,await this.plugin.saveSettings()})),new F.Setting(e).setName("Idle timeout (minutes)").setDesc("Channel sessions with no activity for this long get their subprocess hibernated. State is preserved and the next message resumes transparently.").addSlider(d=>d.setLimits(1,120,1).setValue(this.plugin.settings.channelIdleTimeoutMinutes).setDynamicTooltip().onChange(async u=>{this.plugin.settings.channelIdleTimeoutMinutes=u,await this.plugin.saveSettings()})),new F.Setting(e).setName("Rate limit per conversation").setDesc("Maximum messages allowed per external conversation within the rolling window.").addSlider(d=>d.setLimits(1,100,1).setValue(this.plugin.settings.channelRateLimitPerConversation).setDynamicTooltip().onChange(async u=>{this.plugin.settings.channelRateLimitPerConversation=u,await this.plugin.saveSettings()})),new F.Setting(e).setName("Rate limit window (minutes)").addSlider(d=>d.setLimits(1,60,1).setValue(this.plugin.settings.channelRateLimitWindowMinutes).setDynamicTooltip().onChange(async u=>{this.plugin.settings.channelRateLimitWindowMinutes=u,await this.plugin.saveSettings()})),new F.Setting(e).setName("Channel credentials").setHeading();let a=e.createDiv({cls:"af-channel-credentials"});this.renderCredentialList(a);let i=e.createDiv({cls:"af-channel-credential-add"});i.setCssStyles({marginTop:"12px"}),i.setCssStyles({padding:"12px"}),i.setCssStyles({border:"1px dashed var(--background-modifier-border)"}),i.setCssStyles({borderRadius:"6px"}),i.createEl("strong",{text:"Add a channel credential"});let o={ref:"",type:"slack",botToken:"",appToken:""};new F.Setting(i).setName("Reference name").setDesc("Used by `credential_ref` in _fleet/channels/*.md files.").addText(d=>d.setPlaceholder("my-creds").onChange(u=>{o.ref=u.trim()})),new F.Setting(i).setName("Type").addDropdown(d=>d.addOption("slack","Slack").addOption("telegram","Telegram").addOption("discord","Discord").setValue("slack").onChange(u=>{o.type=u,c.setCssStyles({display:u==="slack"?"":"none"}),l.setCssStyles({display:u==="telegram"?"":"none"}),h.setCssStyles({display:u==="discord"?"":"none"})}));let c=i.createDiv();new F.Setting(c).setName("Bot token (xoxb-...)").addText(d=>{d.inputEl.type="password",d.setPlaceholder("xoxb-...").onChange(u=>{o.botToken=u.trim()})}),new F.Setting(c).setName("App-level token (xapp-...)").setDesc("Generated in your Slack app's Basic Information \u2192 App-Level Tokens.").addText(d=>{d.inputEl.type="password",d.setPlaceholder("xapp-...").onChange(u=>{o.appToken=u.trim()})});let l=i.createDiv();l.setCssStyles({display:"none"}),new F.Setting(l).setName("Bot token").setDesc("From @BotFather on Telegram.").addText(d=>{d.inputEl.type="password",d.setPlaceholder("123456:ABC-DEF1234...").onChange(u=>{o.botToken=u.trim()})});let h=i.createDiv();h.setCssStyles({display:"none"}),new F.Setting(h).setName("Bot token").setDesc("From the Discord Developer Portal \u2192 your application \u2192 Bot \u2192 Reset Token. Enable the Message Content intent on the same page.").addText(d=>{d.inputEl.type="password",d.setPlaceholder("MTA...").onChange(u=>{o.botToken=u.trim()})}),new F.Setting(i).addButton(d=>d.setButtonText("Add credential").setCta().onClick(async()=>{if(!o.ref||!o.botToken){new F.Notice("Fill in the reference name and bot token.");return}let u;if(o.type==="telegram")u={type:"telegram",botToken:o.botToken};else if(o.type==="discord")u={type:"discord",botToken:o.botToken};else{if(!o.appToken){new F.Notice("Slack requires both bot token and app-level token.");return}u={type:"slack",botToken:o.botToken,appToken:o.appToken}}this.plugin.channelCredentials.set(o.ref,u),new F.Notice(`Added credential \`${o.ref}\`.`),this.display()}))}renderCredentialList(e){let s=this.plugin.channelCredentials.list();if(s.length===0){e.createDiv({text:"No channel credentials configured yet.",cls:"af-muted"}).setCssStyles({color:"var(--text-muted)"});return}for(let{ref:n,entry:a}of s){let i=e.createDiv({cls:"af-channel-credential-row"});i.setCssStyles({display:"flex"}),i.setCssStyles({justifyContent:"space-between"}),i.setCssStyles({alignItems:"center"}),i.setCssStyles({padding:"8px 12px"}),i.setCssStyles({border:"1px solid var(--background-modifier-border)"}),i.setCssStyles({borderRadius:"6px"}),i.setCssStyles({marginBottom:"6px"});let o=i.createDiv();o.createEl("strong",{text:n}),o.createEl("span",{text:` \xB7 ${a.type} \xB7 ${Ml(Il(a))}`,cls:"af-muted"}).setCssStyles({color:"var(--text-muted)"});let c=i.createEl("button",{text:"Remove"});c.onclick=()=>{this.plugin.channelCredentials.delete(n),new F.Notice(`Removed credential \`${n}\`.`),this.display()}}}renderWikiKeepersSection(e){new F.Setting(e).setName("Wiki Keepers").setHeading();let s=e.createEl("p",{cls:"af-settings-hint",text:"Per-scope wiki agents. Each runs its own inbox + watched folders + topics + heartbeat. All fields on the Add form are optional \u2014 click Create with everything blank to get a whole-vault keeper with defaults."});s.setCssStyles({color:"var(--af-text-secondary)"}),s.setCssStyles({fontSize:"12px"});let a=this.plugin.runtime.getSnapshot().agents.filter(o=>o.wikiKeeper!==void 0),i=e.createDiv({cls:"af-wk-list"});if(a.length===0)i.createDiv({cls:"af-wk-empty",text:"No Wiki Keepers yet. Click Add to create one."});else for(let o of a){let c=i.createDiv({cls:"af-wk-row"}),l=c.createDiv({cls:"af-wk-row-left"});l.createSpan({cls:"af-wk-name",text:o.name});let h=o.wikiKeeper.scopeRoot||"(whole vault)";l.createSpan({cls:"af-wk-scope",text:`scope: ${h}`});let d=c.createDiv({cls:"af-wk-row-actions"}),u=d.createEl("button",{text:"Edit",cls:"af-wk-row-btn"});u.onclick=()=>{new oa(this.plugin,o,()=>{this.scheduleRerender()}).open()};let p=d.createEl("button",{text:"Delete",cls:"af-wk-row-btn af-wk-row-btn-danger"});p.onclick=()=>{new qt(this.plugin.app,{title:`Delete Wiki Keeper "${o.name}"?`,body:`This removes the agent folder at _fleet/agents/${o.name}/.
|
|
11773
|
-
|
|
11774
|
-
Your scope's inbox, topics, index, and log are NOT deleted.`,confirmText:"Delete",danger:!0,onConfirm:async()=>{try{await Hr(this.plugin.app,this.plugin.settings.fleetFolder,o.name),await this.plugin.refreshFromVault(),new F.Notice(`Wiki Keeper "${o.name}" deleted.`),this.scheduleRerender()}catch(m){let f=m instanceof Error?m.message:String(m);new F.Notice(`Failed to delete: ${f}`)}}}).open()}}new F.Setting(e).setName("Add Wiki Keeper").setDesc("Create a new scoped wiki agent. All fields optional.").addButton(o=>o.setButtonText("+ Add").onClick(()=>{new ia(this.plugin,()=>{this.scheduleRerender()}).open()}))}scheduleRerender(){window.setTimeout(()=>{(async()=>{try{await this.plugin.refreshFromVault()}catch{}this.display()})()},600)}},ia=class extends F.Modal{constructor(e,s){super(e.app);this.plugin=e;this.onCreated=s;this.input=na()}input;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("af-wk-modal"),e.createEl("h2",{text:"Add Wiki Keeper"});let s=e.createDiv({cls:"af-wk-banner"});s.createEl("strong",{text:"All fields are optional. "}),s.createSpan({text:"Click Create with everything blank and you'll get a whole-vault keeper with sensible defaults (inbox at _sources/inbox, topics at topics/, nightly ingest at 3am, Sunday lint)."}),e.createEl("h3",{text:"Scope",cls:"af-wk-section-h"}),new F.Setting(e).setName("Scope folder").setDesc("Optional. Vault-relative path. Empty = whole vault.").addText(h=>h.setPlaceholder("(empty = whole vault)").setValue(this.input.scopeRoot).onChange(d=>{this.input.scopeRoot=d.trim(),this.renderPreview()})),new F.Setting(e).setName("Slug").setDesc("Optional. Agent name suffix. Default: derived from scope folder name, or 'wiki-keeper' for whole-vault.").addText(h=>h.setPlaceholder("(auto)").setValue(this.input.scopeSlug).onChange(d=>{this.input.scopeSlug=d.trim(),this.renderPreview()})),this.renderPreview(),e.createEl("h3",{text:"Sources",cls:"af-wk-section-h"}),new F.Setting(e).setName("Watched folders").setDesc("Optional. Comma- or newline-separated vault-relative paths. Read-only \u2014 claims are extracted but files are never moved. Leave empty for inbox-only mode (you drop files into _sources/inbox/ and they get archived after processing).").addTextArea(h=>h.setPlaceholder("(empty = inbox-only)").setValue(this.input.watchedFolders.join(", ")).onChange(d=>{this.input.watchedFolders=d.split(/[,\n]/).map(u=>u.trim()).filter(Boolean)})),new F.Setting(e).setName("Exclude patterns").setDesc("Optional. Glob patterns to skip. Leave empty to process everything under watched + inbox.").addTextArea(h=>h.setPlaceholder("(empty = no excludes)").setValue(this.input.excludePatterns.join(", ")).onChange(d=>{this.input.excludePatterns=d.split(/[,\n]/).map(u=>u.trim()).filter(Boolean)})),new F.Setting(e).setName("Watch files modified since").setDesc("Watched mode only \u2014 files whose last modification date is before this are skipped. Defaults to today so an established vault doesn't flood the keeper on first run. Clear the field to process everything.").addText(h=>{h.inputEl.type="date",h.setValue(this.input.watchedSince).onChange(d=>{this.input.watchedSince=d.trim()})});let n=this.plugin.runtime.getSnapshot().channels.map(h=>h.name);new F.Setting(e).setName("Heartbeat channel").setDesc("Optional. Slack/Telegram channel for ingest + lint summaries. Leave as (none) to disable.").addDropdown(h=>{h.addOption("","(none)");for(let d of n)h.addOption(d,d);h.setValue(this.input.heartbeatChannel).onChange(d=>{this.input.heartbeatChannel=d})}),e.createEl("h3",{text:"Advanced",cls:"af-wk-section-h"}),new F.Setting(e).setName("Max tokens per ingest").setDesc("Hard cap on token spend per run. Unprocessed files resume next cycle.").addText(h=>h.setValue(String(this.input.maxTokensPerIngest)).onChange(d=>{let u=parseInt(d,10);!isNaN(u)&&u>0&&(this.input.maxTokensPerIngest=u)})),new F.Setting(e).setName("File substantive answers").setDesc("If on, wiki-query files long answers under _topics/syntheses/. Off = answers live only in chat.").addToggle(h=>h.setValue(this.input.fileSubstantiveAnswers).onChange(d=>{this.input.fileSubstantiveAnswers=d})),new F.Setting(e).setName("Obsidian URL scheme for citations").setDesc("If on, external-channel (Slack/Telegram) replies rewrite [[wikilinks]] as obsidian:// URLs.").addToggle(h=>h.setValue(this.input.obsidianUrlScheme).onChange(d=>{this.input.obsidianUrlScheme=d}));let a=e.createEl("h3",{text:"Paths (expert)",cls:"af-wk-section-h"});a.title="Paths are relative to scope_root. Defaults work for almost everyone. Override only if your vault layout demands it \u2014 these cannot be changed after creation.";let i=(h,d,u)=>{new F.Setting(e).setName(h).setDesc(d).addText(p=>p.setPlaceholder(String(this.input[u]??"")).setValue(String(this.input[u]??"")).onChange(m=>{this.input[u]=m.trim()||Br[u]}))};i("Inbox path","Where one-off source drops land.","inboxPath"),i("Archive path","Where processed inbox files are moved after summarization.","archivePath"),i("Topics root","Folder under scope_root that holds the generated topic pages.","topicsRoot"),i("Index path","Relative file path for the curated index.","indexPath"),i("Log path","Relative file path for the keeper's activity log.","logPath"),i("State file","Hidden JSON file that tracks watched-source mtimes.","stateFile");let o=e.createDiv({cls:"af-wk-modal-footer"}),c=o.createEl("button",{text:"Cancel"});c.onclick=()=>this.close();let l=o.createEl("button",{text:"Create",cls:"mod-cta"});l.onclick=async()=>{l.setText("Creating\u2026"),l.disabled=!0;try{let{name:h}=await jr(this.app.vault,this.plugin.settings.fleetFolder,this.input);await this.plugin.refreshFromVault(),this.close(),new F.Notice(`Wiki Keeper "${h}" created.`),this.onCreated()}catch(h){let d=h instanceof Error?h.message:String(h);new F.Notice(`Failed to create Wiki Keeper: ${d}`),l.setText("Create"),l.disabled=!1}}}renderPreview(){let e=this.contentEl.querySelector(".af-wk-name-preview");e||(e=this.contentEl.createDiv({cls:"af-wk-name-preview"}));let s=this.input.scopeSlug||this.input.scopeRoot;e.setText(`\u2192 Will create agent: ${aa(s)}`)}onClose(){this.contentEl.empty()}},oa=class extends F.Modal{constructor(e,s,n){super(e.app);this.plugin=e;this.agent=s;this.onSaved=n;let a=s.wikiKeeper;this.edit={watchedFolders:[...a.watchedFolders],excludePatterns:[...a.excludePatterns],watchedSince:a.watchedSince,heartbeatChannel:s.heartbeatChannel??"",fileSubstantiveAnswers:a.fileSubstantiveAnswers,obsidianUrlScheme:a.obsidianUrlScheme,maxTokensPerIngest:a.maxTokensPerIngest,maxTokensPerRefresh:a.maxTokensPerRefresh,indexSplitThreshold:a.indexSplitThreshold,dedupSimilarityThreshold:a.dedupSimilarityThreshold,summaryStaleDays:a.summaryStaleDays}}edit;onOpen(){let{contentEl:e}=this;e.empty(),e.addClass("af-wk-modal"),e.createEl("h2",{text:`Edit ${this.agent.name}`});let s=e.createDiv({cls:"af-wk-banner"}),n=this.agent.wikiKeeper.scopeRoot||"(whole vault)";s.createEl("strong",{text:"Scope: "}),s.createSpan({text:n}),s.createEl("br"),s.createSpan({text:"Scope and paths are fixed after creation \u2014 changing them would orphan existing topic pages. To move a Wiki Keeper, delete this one and create a new one at the new scope."}),e.createEl("h3",{text:"Sources",cls:"af-wk-section-h"}),new F.Setting(e).setName("Watched folders").setDesc("Comma- or newline-separated vault-relative paths.").addTextArea(l=>l.setValue(this.edit.watchedFolders.join(", ")).onChange(h=>{this.edit.watchedFolders=h.split(/[,\n]/).map(d=>d.trim()).filter(Boolean)})),new F.Setting(e).setName("Exclude patterns").setDesc("Glob patterns to skip.").addTextArea(l=>l.setValue(this.edit.excludePatterns.join(", ")).onChange(h=>{this.edit.excludePatterns=h.split(/[,\n]/).map(d=>d.trim()).filter(Boolean)})),new F.Setting(e).setName("Watch files modified since").setDesc("Watched mode skips files older than this date. Clear to process everything.").addText(l=>{l.inputEl.type="date",l.setValue(this.edit.watchedSince).onChange(h=>{this.edit.watchedSince=h.trim()})});let a=this.plugin.runtime.getSnapshot().channels.map(l=>l.name);new F.Setting(e).setName("Heartbeat channel").addDropdown(l=>{l.addOption("","(none)");for(let h of a)l.addOption(h,h);l.setValue(this.edit.heartbeatChannel).onChange(h=>{this.edit.heartbeatChannel=h})}),e.createEl("h3",{text:"Advanced",cls:"af-wk-section-h"}),new F.Setting(e).setName("Max tokens per ingest").addText(l=>l.setValue(String(this.edit.maxTokensPerIngest)).onChange(h=>{let d=parseInt(h,10);!isNaN(d)&&d>0&&(this.edit.maxTokensPerIngest=d)})),new F.Setting(e).setName("Max tokens per refresh").setDesc("Separate budget for the synthesis-refresh phase that regenerates topic-page summaries.").addText(l=>l.setValue(String(this.edit.maxTokensPerRefresh)).onChange(h=>{let d=parseInt(h,10);!isNaN(d)&&d>0&&(this.edit.maxTokensPerRefresh=d)})),new F.Setting(e).setName("Index split threshold").setDesc("Topic-page count above which index.md splits into per-type sub-MOCs.").addText(l=>l.setValue(String(this.edit.indexSplitThreshold)).onChange(h=>{let d=parseInt(h,10);!isNaN(d)&&d>0&&(this.edit.indexSplitThreshold=d)})),new F.Setting(e).setName("Summary stale (days)").setDesc("Lint flags topic-page summaries older than this and chains wiki-refresh.").addText(l=>l.setValue(String(this.edit.summaryStaleDays)).onChange(h=>{let d=parseInt(h,10);!isNaN(d)&&d>0&&(this.edit.summaryStaleDays=d)})),new F.Setting(e).setName("Dedup similarity threshold").setDesc("Levenshtein-ratio above which lint proposes merging two same-type pages (0.0\u20131.0).").addText(l=>l.setValue(String(this.edit.dedupSimilarityThreshold)).onChange(h=>{let d=parseFloat(h);!isNaN(d)&&d>0&&d<=1&&(this.edit.dedupSimilarityThreshold=d)})),new F.Setting(e).setName("File substantive answers").setDesc("Compounding: wiki-query files long answers under _topics/syntheses/ and bullets each cited topic page. Default ON.").addToggle(l=>l.setValue(this.edit.fileSubstantiveAnswers).onChange(h=>{this.edit.fileSubstantiveAnswers=h})),new F.Setting(e).setName("Obsidian URL scheme for citations").setDesc("Rewrite [[wikilinks]] as obsidian:// URLs when replying via Slack/Telegram.").addToggle(l=>l.setValue(this.edit.obsidianUrlScheme).onChange(h=>{this.edit.obsidianUrlScheme=h}));let i=e.createDiv({cls:"af-wk-modal-footer"}),o=i.createEl("button",{text:"Cancel"});o.onclick=()=>this.close();let c=i.createEl("button",{text:"Save",cls:"mod-cta"});c.onclick=async()=>{c.setText("Saving\u2026"),c.disabled=!0;try{await Wr(this.app.vault,this.plugin.settings.fleetFolder,this.agent.name,this.edit),await this.plugin.refreshFromVault(),this.close(),new F.Notice("Saved."),this.onSaved()}catch(l){let h=l instanceof Error?l.message:String(l);new F.Notice(`Failed to save: ${h}`),c.setText("Save"),c.disabled=!1}}}onClose(){this.contentEl.empty()}};function Il(r){return r.type==="slack",r.botToken}function Ml(r){return r.length<=10?"***":`${r.slice(0,6)}\u2026${r.slice(-4)}`}var Sa=require("crypto");function He(r,t,e,s,n,a,i,o){return He.fromTZ(He.tp(r,t,e,s,n,a,i),o)}He.fromTZISO=(r,t,e)=>He.fromTZ(Ll(r,t),e);He.fromTZ=function(r,t){let e=new Date(Date.UTC(r.y,r.m-1,r.d,r.h,r.i,r.s)),s=la(r.tz,e),n=new Date(e.getTime()-s),a=la(r.tz,n);if(a-s===0)return n;{let i=new Date(e.getTime()-a),o=la(r.tz,i);if(o-a===0)return i;if(!t&&o-a>0)return i;if(t)throw new Error("Invalid date passed to fromTZ()");return n}};He.toTZ=function(r,t){let e=r.toLocaleString("en-US",{timeZone:t}).replace(/[\u202f]/," "),s=new Date(e);return{y:s.getFullYear(),m:s.getMonth()+1,d:s.getDate(),h:s.getHours(),i:s.getMinutes(),s:s.getSeconds(),tz:t}};He.tp=(r,t,e,s,n,a,i)=>({y:r,m:t,d:e,h:s,i:n,s:a,tz:i});function la(r,t=new Date){let e=t.toLocaleString("en-US",{timeZone:r,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],s=t.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${s} GMT`)-Date.parse(`${s} ${e}`)}function Ll(r,t){let e=new Date(Date.parse(r));if(isNaN(e))throw new Error("minitz: Invalid ISO8601 passed to parser.");let s=r.substring(9);return r.includes("Z")||s.includes("-")||s.includes("+")?He.tp(e.getUTCFullYear(),e.getUTCMonth()+1,e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),"Etc/UTC"):He.tp(e.getFullYear(),e.getMonth()+1,e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),t)}He.minitz=He;function Fl(r){if(r===void 0&&(r={}),delete r.name,r.legacyMode=r.legacyMode===void 0?!0:r.legacyMode,r.paused=r.paused===void 0?!1:r.paused,r.maxRuns=r.maxRuns===void 0?1/0:r.maxRuns,r.catch=r.catch===void 0?!1:r.catch,r.interval=r.interval===void 0?0:parseInt(r.interval,10),r.utcOffset=r.utcOffset===void 0?void 0:parseInt(r.utcOffset,10),r.unref=r.unref===void 0?!1:r.unref,r.startAt&&(r.startAt=new _e(r.startAt,r.timezone)),r.stopAt&&(r.stopAt=new _e(r.stopAt,r.timezone)),r.interval!==null){if(isNaN(r.interval))throw new Error("CronOptions: Supplied value for interval is not a number");if(r.interval<0)throw new Error("CronOptions: Supplied value for interval can not be negative")}if(r.utcOffset!==void 0){if(isNaN(r.utcOffset))throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");if(r.utcOffset<-870||r.utcOffset>870)throw new Error("CronOptions: utcOffset out of bounds.");if(r.utcOffset!==void 0&&r.timezone)throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}if(r.unref!==!0&&r.unref!==!1)throw new Error("CronOptions: Unref should be either true, false or undefined(false).");return r}var ca=32,ms=31|ca,zr=[1,2,4,8,16];function Ge(r,t){this.pattern=r,this.timezone=t,this.second=Array(60).fill(0),this.minute=Array(60).fill(0),this.hour=Array(24).fill(0),this.day=Array(31).fill(0),this.month=Array(12).fill(0),this.dayOfWeek=Array(7).fill(0),this.lastDayOfMonth=!1,this.starDOM=!1,this.starDOW=!1,this.parse()}Ge.prototype.parse=function(){if(!(typeof this.pattern=="string"||this.pattern.constructor===String))throw new TypeError("CronPattern: Pattern has to be of type string.");this.pattern.indexOf("@")>=0&&(this.pattern=this.handleNicknames(this.pattern).trim());let r=this.pattern.replace(/\s+/g," ").split(" ");if(r.length<5||r.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exactly five or six space separated parts are required.");if(r.length===5&&r.unshift("0"),r[3].indexOf("L")>=0&&(r[3]=r[3].replace("L",""),this.lastDayOfMonth=!0),r[3]=="*"&&(this.starDOM=!0),r[4].length>=3&&(r[4]=this.replaceAlphaMonths(r[4])),r[5].length>=3&&(r[5]=this.replaceAlphaDays(r[5])),r[5]=="*"&&(this.starDOW=!0),this.pattern.indexOf("?")>=0){let t=new _e(new Date,this.timezone).getDate(!0);r[0]=r[0].replace("?",t.getSeconds()),r[1]=r[1].replace("?",t.getMinutes()),r[2]=r[2].replace("?",t.getHours()),this.starDOM||(r[3]=r[3].replace("?",t.getDate())),r[4]=r[4].replace("?",t.getMonth()+1),this.starDOW||(r[5]=r[5].replace("?",t.getDay()))}this.throwAtIllegalCharacters(r),this.partToArray("second",r[0],0,1),this.partToArray("minute",r[1],0,1),this.partToArray("hour",r[2],0,1),this.partToArray("day",r[3],-1,1),this.partToArray("month",r[4],-1,1),this.partToArray("dayOfWeek",r[5],0,ms),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])};Ge.prototype.partToArray=function(r,t,e,s){let n=this[r],a=r==="day"&&this.lastDayOfMonth;if(t===""&&!a)throw new TypeError("CronPattern: configuration entry "+r+" ("+t+") is empty, check for trailing spaces.");if(t==="*")return n.fill(s);let i=t.split(",");if(i.length>1)for(let o=0;o<i.length;o++)this.partToArray(r,i[o],e,s);else t.indexOf("-")!==-1&&t.indexOf("/")!==-1?this.handleRangeWithStepping(t,r,e,s):t.indexOf("-")!==-1?this.handleRange(t,r,e,s):t.indexOf("/")!==-1?this.handleStepping(t,r,e,s):t!==""&&this.handleNumber(t,r,e,s)};Ge.prototype.throwAtIllegalCharacters=function(r){for(let t=0;t<r.length;t++)if((t===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(r[t]))throw new TypeError("CronPattern: configuration entry "+t+" ("+r[t]+") contains illegal characters.")};Ge.prototype.handleNumber=function(r,t,e,s){let n=this.extractNth(r,t),a=parseInt(n[0],10)+e;if(isNaN(a))throw new TypeError("CronPattern: "+t+" is not a number: '"+r+"'");this.setPart(t,a,n[1]||s)};Ge.prototype.setPart=function(r,t,e){if(!Object.prototype.hasOwnProperty.call(this,r))throw new TypeError("CronPattern: Invalid part specified: "+r);if(r==="dayOfWeek"){if(t===7&&(t=0),(t<0||t>6)&&t!=="L")throw new RangeError("CronPattern: Invalid value for dayOfWeek: "+t);this.setNthWeekdayOfMonth(t,e);return}if(r==="second"||r==="minute"){if(t<0||t>=60)throw new RangeError("CronPattern: Invalid value for "+r+": "+t)}else if(r==="hour"){if(t<0||t>=24)throw new RangeError("CronPattern: Invalid value for "+r+": "+t)}else if(r==="day"){if(t<0||t>=31)throw new RangeError("CronPattern: Invalid value for "+r+": "+t)}else if(r==="month"&&(t<0||t>=12))throw new RangeError("CronPattern: Invalid value for "+r+": "+t);this[r][t]=e};Ge.prototype.handleRangeWithStepping=function(r,t,e,s){let n=this.extractNth(r,t),a=n[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(a===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+r+"'");let[,i,o,c]=a;if(i=parseInt(i,10)+e,o=parseInt(o,10)+e,c=parseInt(c,10),isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(c))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(c===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(c>this[t].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[t].length+")");if(i>o)throw new TypeError("CronPattern: From value is larger than to value: '"+r+"'");for(let l=i;l<=o;l+=c)this.setPart(t,l,n[1]||s)};Ge.prototype.extractNth=function(r,t){let e=r,s;if(e.includes("#")){if(t!=="dayOfWeek")throw new Error("CronPattern: nth (#) only allowed in day-of-week field");s=e.split("#")[1],e=e.split("#")[0]}return[e,s]};Ge.prototype.handleRange=function(r,t,e,s){let n=this.extractNth(r,t),a=n[0].split("-");if(a.length!==2)throw new TypeError("CronPattern: Syntax error, illegal range: '"+r+"'");let i=parseInt(a[0],10)+e,o=parseInt(a[1],10)+e;if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(i>o)throw new TypeError("CronPattern: From value is larger than to value: '"+r+"'");for(let c=i;c<=o;c++)this.setPart(t,c,n[1]||s)};Ge.prototype.handleStepping=function(r,t,e,s){let n=this.extractNth(r,t),a=n[0].split("/");if(a.length!==2)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+r+"'");let i=0;a[0]!=="*"&&(i=parseInt(a[0],10)+e);let o=parseInt(a[1],10);if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(o===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(o>this[t].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[t].length+")");for(let c=i;c<this[t].length;c+=o)this.setPart(t,c,n[1]||s)};Ge.prototype.replaceAlphaDays=function(r){return r.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};Ge.prototype.replaceAlphaMonths=function(r){return r.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};Ge.prototype.handleNicknames=function(r){let t=r.trim().toLowerCase();return t==="@yearly"||t==="@annually"?"0 0 1 1 *":t==="@monthly"?"0 0 1 * *":t==="@weekly"?"0 0 * * 0":t==="@daily"?"0 0 * * *":t==="@hourly"?"0 * * * *":r};Ge.prototype.setNthWeekdayOfMonth=function(r,t){if(t==="L")this.dayOfWeek[r]=this.dayOfWeek[r]|ca;else if(t<6&&t>0)this.dayOfWeek[r]=this.dayOfWeek[r]|zr[t-1];else if(t===ms)this.dayOfWeek[r]=ms;else throw new TypeError(`CronPattern: nth weekday of of range, should be 1-5 or L. Value: ${t}`)};var Gr=[31,28,31,30,31,30,31,31,30,31,30,31],ft=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function _e(r,t){if(this.tz=t,r&&r instanceof Date)if(!isNaN(r))this.fromDate(r);else throw new TypeError("CronDate: Invalid date passed to CronDate constructor");else if(r===void 0)this.fromDate(new Date);else if(r&&typeof r=="string")this.fromString(r);else if(r instanceof _e)this.fromCronDate(r);else throw new TypeError("CronDate: Invalid type ("+typeof r+") passed to CronDate constructor")}_e.prototype.isNthWeekdayOfMonth=function(r,t,e,s){let a=new Date(Date.UTC(r,t,e)).getUTCDay(),i=0;for(let o=1;o<=e;o++)new Date(Date.UTC(r,t,o)).getUTCDay()===a&&i++;if(s&ms&&zr[i-1]&s)return!0;if(s&ca){let o=new Date(Date.UTC(r,t+1,0)).getUTCDate();for(let c=e+1;c<=o;c++)if(new Date(Date.UTC(r,t,c)).getUTCDay()===a)return!1;return!0}return!1};_e.prototype.fromDate=function(r){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=r.getUTCMilliseconds(),this.second=r.getUTCSeconds(),this.minute=r.getUTCMinutes()+this.tz,this.hour=r.getUTCHours(),this.day=r.getUTCDate(),this.month=r.getUTCMonth(),this.year=r.getUTCFullYear(),this.apply();else{let t=He.toTZ(r,this.tz);this.ms=r.getMilliseconds(),this.second=t.s,this.minute=t.i,this.hour=t.h,this.day=t.d,this.month=t.m-1,this.year=t.y}else this.ms=r.getMilliseconds(),this.second=r.getSeconds(),this.minute=r.getMinutes(),this.hour=r.getHours(),this.day=r.getDate(),this.month=r.getMonth(),this.year=r.getFullYear()};_e.prototype.fromCronDate=function(r){this.tz=r.tz,this.year=r.year,this.month=r.month,this.day=r.day,this.hour=r.hour,this.minute=r.minute,this.second=r.second,this.ms=r.ms};_e.prototype.apply=function(){if(this.month>11||this.day>Gr[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let r=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return this.ms=r.getUTCMilliseconds(),this.second=r.getUTCSeconds(),this.minute=r.getUTCMinutes(),this.hour=r.getUTCHours(),this.day=r.getUTCDate(),this.month=r.getUTCMonth(),this.year=r.getUTCFullYear(),!0}else return!1};_e.prototype.fromString=function(r){if(typeof this.tz=="number"){let t=He.fromTZISO(r);this.ms=t.getUTCMilliseconds(),this.second=t.getUTCSeconds(),this.minute=t.getUTCMinutes(),this.hour=t.getUTCHours(),this.day=t.getUTCDate(),this.month=t.getUTCMonth(),this.year=t.getUTCFullYear(),this.apply()}else return this.fromDate(He.fromTZISO(r,this.tz))};_e.prototype.findNext=function(r,t,e,s){let n=this[t],a;e.lastDayOfMonth&&(this.month!==1?a=Gr[this.month]:a=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let i=!e.starDOW&&t=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let o=this[t]+s;o<e[t].length;o++){let c=e[t][o];if(t==="day"&&e.lastDayOfMonth&&o-s==a&&(c=!0),t==="day"&&!e.starDOW){let l=e.dayOfWeek[(i+(o-s-1))%7];if(l&&l&ms)l=this.isNthWeekdayOfMonth(this.year,this.month,o-s,l);else if(l)throw new Error(`CronDate: Invalid value for dayOfWeek encountered. ${l}`);r.legacyMode&&!e.starDOM?c=c||l:c=c&&l}if(c)return this[t]=o-s,n!==this[t]?2:1}return 3};_e.prototype.recurse=function(r,t,e){let s=this.findNext(t,ft[e][0],r,ft[e][2]);if(s>1){let n=e+1;for(;n<ft.length;)this[ft[n][0]]=-ft[n][2],n++;if(s===3)return this[ft[e][1]]++,this[ft[e][0]]=-ft[e][2],this.apply(),this.recurse(r,t,0);if(this.apply())return this.recurse(r,t,e-1)}return e+=1,e>=ft.length?this:this.year>=3e3?null:this.recurse(r,t,e)};_e.prototype.increment=function(r,t,e){return this.second+=t.interval>1&&e?t.interval:1,this.ms=0,this.apply(),this.recurse(r,t,0)};_e.prototype.getDate=function(r){return r||this.tz===void 0?new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms):typeof this.tz=="number"?new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms)):He(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)};_e.prototype.getTime=function(){return this.getDate().getTime()};function tn(r){return Object.prototype.toString.call(r)==="[object Function]"||typeof r=="function"||r instanceof Function}function Ol(r){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(r):r&&typeof r.unref<"u"&&r.unref()}var qr=30*1e3,fs=[];function pe(r,t,e){if(!(this instanceof pe))return new pe(r,t,e);let s,n;if(tn(t))n=t;else if(typeof t=="object")s=t;else if(t!==void 0)throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(tn(e))n=e;else if(typeof e=="object")s=e;else if(e!==void 0)throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=s?s.name:void 0,this.options=Fl(s),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:s?s.maxRuns:void 0,paused:s?s.paused:!1,pattern:void 0},r&&(r instanceof Date||typeof r=="string"&&r.indexOf(":")>0)?this._states.once=new _e(r,this.options.timezone||this.options.utcOffset):this._states.pattern=new Ge(r,this.options.timezone),this.name){if(fs.find(i=>i.name===this.name))throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");fs.push(this)}return n!==void 0&&(this.fn=n,this.schedule()),this}pe.prototype.nextRun=function(r){let t=this._next(r);return t?t.getDate():null};pe.prototype.nextRuns=function(r,t){r>this._states.maxRuns&&(r=this._states.maxRuns);let e=[],s=t||this._states.currentRun;for(;r--&&(s=this.nextRun(s));)e.push(s);return e};pe.prototype.getPattern=function(){return this._states.pattern?this._states.pattern.pattern:void 0};pe.prototype.isRunning=function(){let r=this.nextRun(this._states.currentRun),t=!this._states.paused,e=this.fn!==void 0,s=!this._states.kill;return t&&e&&s&&r!==null};pe.prototype.isStopped=function(){return this._states.kill};pe.prototype.isBusy=function(){return this._states.blocking};pe.prototype.currentRun=function(){return this._states.currentRun?this._states.currentRun.getDate():null};pe.prototype.previousRun=function(){return this._states.previousRun?this._states.previousRun.getDate():null};pe.prototype.msToNext=function(r){r=r||new Date;let t=this._next(r);return t?t.getTime()-r.getTime():null};pe.prototype.stop=function(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let r=fs.indexOf(this);r>=0&&fs.splice(r,1)};pe.prototype.pause=function(){return this._states.paused=!0,!this._states.kill};pe.prototype.resume=function(){return this._states.paused=!1,!this._states.kill};pe.prototype.schedule=function(r){if(r&&this.fn)throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");r&&(this.fn=r);let t=this.msToNext(),e=this.nextRun(this._states.currentRun);return t==null||isNaN(t)||e===null?this:(t>qr&&(t=qr),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(e),t),this._states.currentTimeout&&this.options.unref&&Ol(this._states.currentTimeout),this)};pe.prototype._trigger=async function(r){if(this._states.blocking=!0,this._states.currentRun=new _e(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{await this.fn(this,this.options.context)}catch(t){tn(this.options.catch)&&this.options.catch(t,this)}else await this.fn(this,this.options.context);this._states.previousRun=new _e(r,this.options.timezone||this.options.utcOffset),this._states.blocking=!1};pe.prototype.trigger=async function(){await this._trigger()};pe.prototype._checkTrigger=function(r){let t=new Date,e=!this._states.paused&&t.getTime()>=r,s=this._states.blocking&&this.options.protect;e&&!s?(this._states.maxRuns--,this._trigger()):e&&s&&tn(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()};pe.prototype._next=function(r){let t=!!(r||this._states.currentRun),e=!1;!r&&this.options.startAt&&this.options.interval&&([r,t]=this._calculatePreviousRun(r,t),e=!r),r=new _e(r,this.options.timezone||this.options.utcOffset),this.options.startAt&&r&&r.getTime()<this.options.startAt.getTime()&&(r=this.options.startAt);let s=this._states.once||new _e(r,this.options.timezone||this.options.utcOffset);return!e&&s!==this._states.once&&(s=s.increment(this._states.pattern,this.options,t)),this._states.once&&this._states.once.getTime()<=r.getTime()||s===null||this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&s.getTime()>=this.options.stopAt.getTime()?null:s};pe.prototype._calculatePreviousRun=function(r,t){let e=new _e(void 0,this.options.timezone||this.options.utcOffset);if(this.options.startAt.getTime()<=e.getTime()){r=this.options.startAt;let s=r.getTime()+this.options.interval*1e3;for(;s<=e.getTime();)r=new _e(r,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),s=r.getTime()+this.options.interval*1e3;t=!0}return[r,t]};pe.Cron=pe;pe.scheduledJobs=fs;var wi=require("obsidian");var hi=require("crypto");var Je=require("fs"),da=require("path");function Nl(r){return`mcp__${r.replace(/[\s.]+/g,"_")}`}function sn(r,t,e={}){let s=t.permissionRules.allow.length>0||t.permissionRules.deny.length>0,n=t.permissionMode?.trim(),a=!!n&&n!=="default",i=e.mcpAllowServers??[],o=i.length>0;if(!(s||a||o))return null;let l=(0,da.join)(r,".claude"),h=(0,da.join)(l,"settings.local.json");(0,Je.existsSync)(l)||(0,Je.mkdirSync)(l,{recursive:!0});let d=null;if((0,Je.existsSync)(h))try{d=(0,Je.readFileSync)(h,"utf-8")}catch{d=null}let u={};if(a&&(u.defaultMode=n),s||o){let p=[...t.permissionRules.allow];for(let m of i)p.push(Nl(m));u.permissions={allow:p,deny:t.permissionRules.deny}}return(0,Je.writeFileSync)(h,JSON.stringify(u,null,2)+`
|
|
11775
|
-
`,"utf-8"),{path:
|
|
11776
|
-
`);if(
|
|
11777
|
-
`).trim()}
|
|
11778
|
-
\u25B8 ${
|
|
11779
|
-
`)}if(
|
|
11780
|
-
${
|
|
11773
|
+
`),{path:n,name:s}}async function ms(a,e){if(a.getAbstractFileByPath(e))return;let t=e.split("/"),s="";for(let n of t)if(s=s?`${s}/${n}`:n,!a.getAbstractFileByPath(s))try{await a.createFolder(s)}catch(r){if(!(r instanceof Error?r.message:String(r)).includes("already exists"))throw r}}async function Mi(a,e,t){if(a.getAbstractFileByPath(e))return;let s=e.replace(/\/[^/]+$/,"");s&&s!==e&&await ms(a,s),await a.create(e,t)}async function Bi(a,e,t,s){let n=(0,le.normalizePath)(`${e}/agents/${t}`),r=(0,le.normalizePath)(`${n}/config.md`),i=a.getAbstractFileByPath(r);if(!(i instanceof le.TFile))throw new Error(`Config file not found for ${t} at ${r}`);let o=await a.cachedRead(i),{frontmatter:l,body:c}=W(o),d=l.wiki_keeper??{};d.watched_folders=s.watchedFolders,d.exclude_patterns=s.excludePatterns,s.watchedSince?d.watched_since=s.watchedSince:delete d.watched_since,delete d.ingest_schedule,delete d.lint_schedule,delete d.lint_day,d.file_substantive_answers=s.fileSubstantiveAnswers,d.obsidian_url_scheme=s.obsidianUrlScheme,d.max_tokens_per_ingest=s.maxTokensPerIngest,d.max_tokens_per_refresh=s.maxTokensPerRefresh,d.index_split_threshold=s.indexSplitThreshold,d.dedup_similarity_threshold=s.dedupSimilarityThreshold,d.summary_stale_days=s.summaryStaleDays,(typeof d.failed_path!="string"||!d.failed_path)&&(d.failed_path="_sources/failed"),l.wiki_keeper=d,delete l.allowed_tools,delete l.blocked_tools,await a.modify(i,U(l,c)),await Oi(a,n);let u=(0,le.normalizePath)(`${n}/HEARTBEAT.md`),h=a.getAbstractFileByPath(u);if(h instanceof le.TFile){let f=await a.cachedRead(h),{frontmatter:g,body:w}=W(f);s.heartbeatChannel?g.channel=s.heartbeatChannel:delete g.channel,await a.modify(h,U(g,w))}let p=Ja(e,t);a.getAbstractFileByPath(p)instanceof le.TFile||(await ms(a,(0,le.normalizePath)(`${e}/tasks`)),await a.create(p,Li(t)))}async function Ui(a,e,t){let s=a.vault,n=(0,le.normalizePath)(`${e}/agents/${t}`),r=s.getAbstractFileByPath(n);if(!r)return;if(!(r instanceof le.TFolder))throw new Error(`Expected folder at ${n}`);await a.fileManager.trashFile(r);let i=Ja(e,t),o=s.getAbstractFileByPath(i);o instanceof le.TFile&&await a.fileManager.trashFile(o)}var Un=class extends D.PluginSettingTab{constructor(t){super(t.app,t);this.plugin=t}display(){let{containerEl:t}=this;t.empty(),new D.Setting(t).setName("Fleet folder").addText(r=>r.setValue(this.plugin.settings.fleetFolder).onChange(async i=>{this.plugin.settings.fleetFolder=i.trim()||ft.fleetFolder,await this.plugin.saveSettings()})),new D.Setting(t).setName("Claude CLI path").addText(r=>r.setValue(this.plugin.settings.claudeCliPath).onChange(async i=>{this.plugin.settings.claudeCliPath=i.trim()||ft.claudeCliPath,await this.plugin.saveSettings()})),new D.Setting(t).setName("Codex CLI path").setDesc("Used by agents with adapter \u201Ccodex\u201D. Install via `npm i -g @openai/codex` and authenticate with `codex login` in a terminal first.").addText(r=>r.setValue(this.plugin.settings.codexCliPath).onChange(async i=>{this.plugin.settings.codexCliPath=i.trim()||ft.codexCliPath,await this.plugin.saveSettings()}));let n=new D.Setting(t).setName("Default model").setDesc("Fallback for agents that don\u2019t set their own. Aliases (opus/sonnet/haiku) work on any backend; use Custom for pinned IDs or Bedrock/Vertex/Foundry.").controlEl.createDiv();Nt(n,{value:this.plugin.settings.defaultModel,onChange:async r=>{this.plugin.settings.defaultModel=r||ft.defaultModel,await this.plugin.saveSettings()}}),new D.Setting(t).setName("AWS region").addText(r=>r.setValue(this.plugin.settings.awsRegion).onChange(async i=>{this.plugin.settings.awsRegion=i.trim()||ft.awsRegion,await this.plugin.saveSettings()})),new D.Setting(t).setName("Max concurrent runs").addSlider(r=>r.setLimits(1,10,1).setValue(this.plugin.settings.maxConcurrentRuns).setDynamicTooltip().onChange(async i=>{this.plugin.settings.maxConcurrentRuns=i,await this.plugin.saveSettings()})),new D.Setting(t).setName("Run log retention").setDesc("Days to keep run logs before auto-prune.").addSlider(r=>r.setLimits(1,365,1).setValue(this.plugin.settings.runLogRetentionDays).setDynamicTooltip().onChange(async i=>{this.plugin.settings.runLogRetentionDays=i,await this.plugin.saveSettings()})),new D.Setting(t).setName("Catch up missed tasks").addToggle(r=>r.setValue(this.plugin.settings.catchUpMissedTasks).onChange(async i=>{this.plugin.settings.catchUpMissedTasks=i,await this.plugin.saveSettings()})),new D.Setting(t).setName("Notification level").addDropdown(r=>r.addOption("all","All").addOption("failures-only","Failures only").addOption("none","None").setValue(this.plugin.settings.notificationLevel).onChange(async i=>{this.plugin.settings.notificationLevel=i,await this.plugin.saveSettings()})),new D.Setting(t).setName("Status bar").addToggle(r=>r.setValue(this.plugin.settings.showStatusBar).onChange(async i=>{this.plugin.settings.showStatusBar=i,await this.plugin.saveSettings(),this.plugin.refreshStatusBar()})),new D.Setting(t).setName("Chat watchdog timeout (minutes)").setDesc("How long a chat session waits for any output from the Claude CLI before killing the subprocess and surfacing a timeout error. Raise this if your agents run long tools (e.g. large web fetches, builds) and you're seeing spurious 'no response' errors.").addSlider(r=>r.setLimits(1,60,1).setValue(this.plugin.settings.chatWatchdogMinutes).setDynamicTooltip().onChange(async i=>{this.plugin.settings.chatWatchdogMinutes=i,await this.plugin.saveSettings()})),new D.Setting(t).setName("Verify Claude CLI").setDesc("Checks that the configured binary is reachable.").addButton(r=>r.setButtonText("Verify").onClick(async()=>{let i=await this.plugin.verifyClaudeCli();new D.Notice(i?"Claude CLI detected.":"Claude CLI check failed. See console for details.")})),new D.Setting(t).setName("Verify Codex CLI").setDesc("Checks that the configured Codex binary is reachable.").addButton(r=>r.setButtonText("Verify").onClick(async()=>{let i=await this.plugin.verifyCodexCli();new D.Notice(i?"Codex CLI detected.":"Codex CLI check failed. See console for details.")})),this.renderWikiKeepersSection(t),this.renderChannelsSection(t)}renderChannelsSection(t){new D.Setting(t).setName("Channels").setHeading();let s=t.createDiv({cls:"af-settings-warning"});s.setCssStyles({padding:"12px"}),s.setCssStyles({margin:"8px 0 16px 0"}),s.setCssStyles({border:"1px solid var(--background-modifier-border)"}),s.setCssStyles({borderRadius:"6px"}),s.setCssStyles({background:"var(--background-secondary)"}),s.createEl("strong",{text:"Credential storage: "});let n=this.plugin.app.vault.configDir;s.createSpan({text:`Channel credentials are stored in this plugin's data.json inside your vault's ${n} folder. If you sync your ${n} folder across devices, credentials will sync with it. Do not commit this file to a public git repository.`}),new D.Setting(t).setName("Max concurrent channel sessions").setDesc("Hard cap on live claude subprocesses across all channels. Oldest idle session is hibernated when exceeded.").addSlider(u=>u.setLimits(1,20,1).setValue(this.plugin.settings.maxConcurrentChannelSessions).setDynamicTooltip().onChange(async h=>{this.plugin.settings.maxConcurrentChannelSessions=h,await this.plugin.saveSettings()})),new D.Setting(t).setName("Idle timeout (minutes)").setDesc("Channel sessions with no activity for this long get their subprocess hibernated. State is preserved and the next message resumes transparently.").addSlider(u=>u.setLimits(1,120,1).setValue(this.plugin.settings.channelIdleTimeoutMinutes).setDynamicTooltip().onChange(async h=>{this.plugin.settings.channelIdleTimeoutMinutes=h,await this.plugin.saveSettings()})),new D.Setting(t).setName("Rate limit per conversation").setDesc("Maximum messages allowed per external conversation within the rolling window.").addSlider(u=>u.setLimits(1,100,1).setValue(this.plugin.settings.channelRateLimitPerConversation).setDynamicTooltip().onChange(async h=>{this.plugin.settings.channelRateLimitPerConversation=h,await this.plugin.saveSettings()})),new D.Setting(t).setName("Rate limit window (minutes)").addSlider(u=>u.setLimits(1,60,1).setValue(this.plugin.settings.channelRateLimitWindowMinutes).setDynamicTooltip().onChange(async h=>{this.plugin.settings.channelRateLimitWindowMinutes=h,await this.plugin.saveSettings()})),new D.Setting(t).setName("Channel credentials").setHeading();let r=t.createDiv({cls:"af-channel-credentials"});this.renderCredentialList(r);let i=t.createDiv({cls:"af-channel-credential-add"});i.setCssStyles({marginTop:"12px"}),i.setCssStyles({padding:"12px"}),i.setCssStyles({border:"1px dashed var(--background-modifier-border)"}),i.setCssStyles({borderRadius:"6px"}),i.createEl("strong",{text:"Add a channel credential"});let o={ref:"",type:"slack",botToken:"",appToken:""};new D.Setting(i).setName("Reference name").setDesc("Used by `credential_ref` in _fleet/channels/*.md files.").addText(u=>u.setPlaceholder("my-creds").onChange(h=>{o.ref=h.trim()})),new D.Setting(i).setName("Type").addDropdown(u=>u.addOption("slack","Slack").addOption("telegram","Telegram").addOption("discord","Discord").setValue("slack").onChange(h=>{o.type=h,l.setCssStyles({display:h==="slack"?"":"none"}),c.setCssStyles({display:h==="telegram"?"":"none"}),d.setCssStyles({display:h==="discord"?"":"none"})}));let l=i.createDiv();new D.Setting(l).setName("Bot token (xoxb-...)").addText(u=>{u.inputEl.type="password",u.setPlaceholder("xoxb-...").onChange(h=>{o.botToken=h.trim()})}),new D.Setting(l).setName("App-level token (xapp-...)").setDesc("Generated in your Slack app's Basic Information \u2192 App-Level Tokens.").addText(u=>{u.inputEl.type="password",u.setPlaceholder("xapp-...").onChange(h=>{o.appToken=h.trim()})});let c=i.createDiv();c.setCssStyles({display:"none"}),new D.Setting(c).setName("Bot token").setDesc("From @BotFather on Telegram.").addText(u=>{u.inputEl.type="password",u.setPlaceholder("123456:ABC-DEF1234...").onChange(h=>{o.botToken=h.trim()})});let d=i.createDiv();d.setCssStyles({display:"none"}),new D.Setting(d).setName("Bot token").setDesc("From the Discord Developer Portal \u2192 your application \u2192 Bot \u2192 Reset Token. Enable the Message Content intent on the same page.").addText(u=>{u.inputEl.type="password",u.setPlaceholder("MTA...").onChange(h=>{o.botToken=h.trim()})}),new D.Setting(i).addButton(u=>u.setButtonText("Add credential").setCta().onClick(async()=>{if(!o.ref||!o.botToken){new D.Notice("Fill in the reference name and bot token.");return}let h;if(o.type==="telegram")h={type:"telegram",botToken:o.botToken};else if(o.type==="discord")h={type:"discord",botToken:o.botToken};else{if(!o.appToken){new D.Notice("Slack requires both bot token and app-level token.");return}h={type:"slack",botToken:o.botToken,appToken:o.appToken}}this.plugin.channelCredentials.set(o.ref,h),new D.Notice(`Added credential \`${o.ref}\`.`),this.display()}))}renderCredentialList(t){let s=this.plugin.channelCredentials.list();if(s.length===0){t.createDiv({text:"No channel credentials configured yet.",cls:"af-muted"}).setCssStyles({color:"var(--text-muted)"});return}for(let{ref:n,entry:r}of s){let i=t.createDiv({cls:"af-channel-credential-row"});i.setCssStyles({display:"flex"}),i.setCssStyles({justifyContent:"space-between"}),i.setCssStyles({alignItems:"center"}),i.setCssStyles({padding:"8px 12px"}),i.setCssStyles({border:"1px solid var(--background-modifier-border)"}),i.setCssStyles({borderRadius:"6px"}),i.setCssStyles({marginBottom:"6px"});let o=i.createDiv();o.createEl("strong",{text:n}),o.createEl("span",{text:` \xB7 ${r.type} \xB7 ${hd(ud(r))}`,cls:"af-muted"}).setCssStyles({color:"var(--text-muted)"});let l=i.createEl("button",{text:"Remove"});l.onclick=()=>{this.plugin.channelCredentials.delete(n),new D.Notice(`Removed credential \`${n}\`.`),this.display()}}}renderWikiKeepersSection(t){new D.Setting(t).setName("Wiki Keepers").setHeading();let s=t.createEl("p",{cls:"af-settings-hint",text:"Per-scope wiki agents. Each runs its own inbox + watched folders + topics + heartbeat. All fields on the Add form are optional \u2014 click Create with everything blank to get a whole-vault keeper with defaults."});s.setCssStyles({color:"var(--af-text-secondary)"}),s.setCssStyles({fontSize:"12px"});let r=this.plugin.runtime.getSnapshot().agents.filter(o=>o.wikiKeeper!==void 0),i=t.createDiv({cls:"af-wk-list"});if(r.length===0)i.createDiv({cls:"af-wk-empty",text:"No Wiki Keepers yet. Click Add to create one."});else for(let o of r){let l=i.createDiv({cls:"af-wk-row"}),c=l.createDiv({cls:"af-wk-row-left"});c.createSpan({cls:"af-wk-name",text:o.name});let d=o.wikiKeeper.scopeRoot||"(whole vault)";c.createSpan({cls:"af-wk-scope",text:`scope: ${d}`});let u=l.createDiv({cls:"af-wk-row-actions"}),h=u.createEl("button",{text:"Edit",cls:"af-wk-row-btn"});h.onclick=()=>{new Qa(this.plugin,o,()=>{this.scheduleRerender()}).open()};let p=u.createEl("button",{text:"Delete",cls:"af-wk-row-btn af-wk-row-btn-danger"});p.onclick=()=>{new ut(this.plugin.app,{title:`Delete Wiki Keeper "${o.name}"?`,body:`This removes the agent folder at _fleet/agents/${o.name}/.
|
|
11774
|
+
|
|
11775
|
+
Your scope's inbox, topics, index, and log are NOT deleted.`,confirmText:"Delete",danger:!0,onConfirm:async()=>{try{await Ui(this.plugin.app,this.plugin.settings.fleetFolder,o.name),await this.plugin.refreshFromVault(),new D.Notice(`Wiki Keeper "${o.name}" deleted.`),this.scheduleRerender()}catch(m){let f=m instanceof Error?m.message:String(m);new D.Notice(`Failed to delete: ${f}`)}}}).open()}}new D.Setting(t).setName("Add Wiki Keeper").setDesc("Create a new scoped wiki agent. All fields optional.").addButton(o=>o.setButtonText("+ Add").onClick(()=>{new Xa(this.plugin,()=>{this.scheduleRerender()}).open()}))}scheduleRerender(){window.setTimeout(()=>{(async()=>{try{await this.plugin.refreshFromVault()}catch{}this.display()})()},600)}},Xa=class extends D.Modal{constructor(t,s){super(t.app);this.plugin=t;this.onCreated=s;this.input=Ya()}input;onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("af-wk-modal"),t.createEl("h2",{text:"Add Wiki Keeper"});let s=t.createDiv({cls:"af-wk-banner"});s.createEl("strong",{text:"All fields are optional. "}),s.createSpan({text:"Click Create with everything blank and you'll get a whole-vault keeper with sensible defaults (inbox at _sources/inbox, topics at topics/, nightly ingest at 3am, Sunday lint)."}),t.createEl("h3",{text:"Scope",cls:"af-wk-section-h"}),new D.Setting(t).setName("Scope folder").setDesc("Optional. Vault-relative path. Empty = whole vault.").addText(d=>d.setPlaceholder("(empty = whole vault)").setValue(this.input.scopeRoot).onChange(u=>{this.input.scopeRoot=u.trim(),this.renderPreview()})),new D.Setting(t).setName("Slug").setDesc("Optional. Agent name suffix. Default: derived from scope folder name, or 'wiki-keeper' for whole-vault.").addText(d=>d.setPlaceholder("(auto)").setValue(this.input.scopeSlug).onChange(u=>{this.input.scopeSlug=u.trim(),this.renderPreview()})),this.renderPreview(),t.createEl("h3",{text:"Sources",cls:"af-wk-section-h"}),new D.Setting(t).setName("Watched folders").setDesc("Optional. Comma- or newline-separated vault-relative paths. Read-only \u2014 claims are extracted but files are never moved. Leave empty for inbox-only mode (you drop files into _sources/inbox/ and they get archived after processing).").addTextArea(d=>d.setPlaceholder("(empty = inbox-only)").setValue(this.input.watchedFolders.join(", ")).onChange(u=>{this.input.watchedFolders=u.split(/[,\n]/).map(h=>h.trim()).filter(Boolean)})),new D.Setting(t).setName("Exclude patterns").setDesc("Optional. Glob patterns to skip. Leave empty to process everything under watched + inbox.").addTextArea(d=>d.setPlaceholder("(empty = no excludes)").setValue(this.input.excludePatterns.join(", ")).onChange(u=>{this.input.excludePatterns=u.split(/[,\n]/).map(h=>h.trim()).filter(Boolean)})),new D.Setting(t).setName("Watch files modified since").setDesc("Watched mode only \u2014 files whose last modification date is before this are skipped. Defaults to today so an established vault doesn't flood the keeper on first run. Clear the field to process everything.").addText(d=>{d.inputEl.type="date",d.setValue(this.input.watchedSince).onChange(u=>{this.input.watchedSince=u.trim()})});let n=this.plugin.runtime.getSnapshot().channels.map(d=>d.name);new D.Setting(t).setName("Heartbeat channel").setDesc("Optional. Slack/Telegram channel for ingest + lint summaries. Leave as (none) to disable.").addDropdown(d=>{d.addOption("","(none)");for(let u of n)d.addOption(u,u);d.setValue(this.input.heartbeatChannel).onChange(u=>{this.input.heartbeatChannel=u})}),t.createEl("h3",{text:"Advanced",cls:"af-wk-section-h"}),new D.Setting(t).setName("Max tokens per ingest").setDesc("Hard cap on token spend per run. Unprocessed files resume next cycle.").addText(d=>d.setValue(String(this.input.maxTokensPerIngest)).onChange(u=>{let h=parseInt(u,10);!isNaN(h)&&h>0&&(this.input.maxTokensPerIngest=h)})),new D.Setting(t).setName("File substantive answers").setDesc("If on, wiki-query files long answers under _topics/syntheses/. Off = answers live only in chat.").addToggle(d=>d.setValue(this.input.fileSubstantiveAnswers).onChange(u=>{this.input.fileSubstantiveAnswers=u})),new D.Setting(t).setName("Obsidian URL scheme for citations").setDesc("If on, external-channel (Slack/Telegram) replies rewrite [[wikilinks]] as obsidian:// URLs.").addToggle(d=>d.setValue(this.input.obsidianUrlScheme).onChange(u=>{this.input.obsidianUrlScheme=u}));let r=t.createEl("h3",{text:"Paths (expert)",cls:"af-wk-section-h"});r.title="Paths are relative to scope_root. Defaults work for almost everyone. Override only if your vault layout demands it \u2014 these cannot be changed after creation.";let i=(d,u,h)=>{new D.Setting(t).setName(d).setDesc(u).addText(p=>p.setPlaceholder(String(this.input[h]??"")).setValue(String(this.input[h]??"")).onChange(m=>{this.input[h]=m.trim()||Fi[h]}))};i("Inbox path","Where one-off source drops land.","inboxPath"),i("Archive path","Where processed inbox files are moved after summarization.","archivePath"),i("Topics root","Folder under scope_root that holds the generated topic pages.","topicsRoot"),i("Index path","Relative file path for the curated index.","indexPath"),i("Log path","Relative file path for the keeper's activity log.","logPath"),i("State file","Hidden JSON file that tracks watched-source mtimes.","stateFile");let o=t.createDiv({cls:"af-wk-modal-footer"}),l=o.createEl("button",{text:"Cancel"});l.onclick=()=>this.close();let c=o.createEl("button",{text:"Create",cls:"mod-cta"});c.onclick=async()=>{c.setText("Creating\u2026"),c.disabled=!0;try{let{name:d}=await Ni(this.app.vault,this.plugin.settings.fleetFolder,this.input);await this.plugin.refreshFromVault(),this.close(),new D.Notice(`Wiki Keeper "${d}" created.`),this.onCreated()}catch(d){let u=d instanceof Error?d.message:String(d);new D.Notice(`Failed to create Wiki Keeper: ${u}`),c.setText("Create"),c.disabled=!1}}}renderPreview(){let t=this.contentEl.querySelector(".af-wk-name-preview");t||(t=this.contentEl.createDiv({cls:"af-wk-name-preview"}));let s=this.input.scopeSlug||this.input.scopeRoot;t.setText(`\u2192 Will create agent: ${Ka(s)}`)}onClose(){this.contentEl.empty()}},Qa=class extends D.Modal{constructor(t,s,n){super(t.app);this.plugin=t;this.agent=s;this.onSaved=n;let r=s.wikiKeeper;this.edit={watchedFolders:[...r.watchedFolders],excludePatterns:[...r.excludePatterns],watchedSince:r.watchedSince,heartbeatChannel:s.heartbeatChannel??"",fileSubstantiveAnswers:r.fileSubstantiveAnswers,obsidianUrlScheme:r.obsidianUrlScheme,maxTokensPerIngest:r.maxTokensPerIngest,maxTokensPerRefresh:r.maxTokensPerRefresh,indexSplitThreshold:r.indexSplitThreshold,dedupSimilarityThreshold:r.dedupSimilarityThreshold,summaryStaleDays:r.summaryStaleDays}}edit;onOpen(){let{contentEl:t}=this;t.empty(),t.addClass("af-wk-modal"),t.createEl("h2",{text:`Edit ${this.agent.name}`});let s=t.createDiv({cls:"af-wk-banner"}),n=this.agent.wikiKeeper.scopeRoot||"(whole vault)";s.createEl("strong",{text:"Scope: "}),s.createSpan({text:n}),s.createEl("br"),s.createSpan({text:"Scope and paths are fixed after creation \u2014 changing them would orphan existing topic pages. To move a Wiki Keeper, delete this one and create a new one at the new scope."}),t.createEl("h3",{text:"Sources",cls:"af-wk-section-h"}),new D.Setting(t).setName("Watched folders").setDesc("Comma- or newline-separated vault-relative paths.").addTextArea(c=>c.setValue(this.edit.watchedFolders.join(", ")).onChange(d=>{this.edit.watchedFolders=d.split(/[,\n]/).map(u=>u.trim()).filter(Boolean)})),new D.Setting(t).setName("Exclude patterns").setDesc("Glob patterns to skip.").addTextArea(c=>c.setValue(this.edit.excludePatterns.join(", ")).onChange(d=>{this.edit.excludePatterns=d.split(/[,\n]/).map(u=>u.trim()).filter(Boolean)})),new D.Setting(t).setName("Watch files modified since").setDesc("Watched mode skips files older than this date. Clear to process everything.").addText(c=>{c.inputEl.type="date",c.setValue(this.edit.watchedSince).onChange(d=>{this.edit.watchedSince=d.trim()})});let r=this.plugin.runtime.getSnapshot().channels.map(c=>c.name);new D.Setting(t).setName("Heartbeat channel").addDropdown(c=>{c.addOption("","(none)");for(let d of r)c.addOption(d,d);c.setValue(this.edit.heartbeatChannel).onChange(d=>{this.edit.heartbeatChannel=d})}),t.createEl("h3",{text:"Advanced",cls:"af-wk-section-h"}),new D.Setting(t).setName("Max tokens per ingest").addText(c=>c.setValue(String(this.edit.maxTokensPerIngest)).onChange(d=>{let u=parseInt(d,10);!isNaN(u)&&u>0&&(this.edit.maxTokensPerIngest=u)})),new D.Setting(t).setName("Max tokens per refresh").setDesc("Separate budget for the synthesis-refresh phase that regenerates topic-page summaries.").addText(c=>c.setValue(String(this.edit.maxTokensPerRefresh)).onChange(d=>{let u=parseInt(d,10);!isNaN(u)&&u>0&&(this.edit.maxTokensPerRefresh=u)})),new D.Setting(t).setName("Index split threshold").setDesc("Topic-page count above which index.md splits into per-type sub-MOCs.").addText(c=>c.setValue(String(this.edit.indexSplitThreshold)).onChange(d=>{let u=parseInt(d,10);!isNaN(u)&&u>0&&(this.edit.indexSplitThreshold=u)})),new D.Setting(t).setName("Summary stale (days)").setDesc("Lint flags topic-page summaries older than this and chains wiki-refresh.").addText(c=>c.setValue(String(this.edit.summaryStaleDays)).onChange(d=>{let u=parseInt(d,10);!isNaN(u)&&u>0&&(this.edit.summaryStaleDays=u)})),new D.Setting(t).setName("Dedup similarity threshold").setDesc("Levenshtein-ratio above which lint proposes merging two same-type pages (0.0\u20131.0).").addText(c=>c.setValue(String(this.edit.dedupSimilarityThreshold)).onChange(d=>{let u=parseFloat(d);!isNaN(u)&&u>0&&u<=1&&(this.edit.dedupSimilarityThreshold=u)})),new D.Setting(t).setName("File substantive answers").setDesc("Compounding: wiki-query files long answers under _topics/syntheses/ and bullets each cited topic page. Default ON.").addToggle(c=>c.setValue(this.edit.fileSubstantiveAnswers).onChange(d=>{this.edit.fileSubstantiveAnswers=d})),new D.Setting(t).setName("Obsidian URL scheme for citations").setDesc("Rewrite [[wikilinks]] as obsidian:// URLs when replying via Slack/Telegram.").addToggle(c=>c.setValue(this.edit.obsidianUrlScheme).onChange(d=>{this.edit.obsidianUrlScheme=d}));let i=t.createDiv({cls:"af-wk-modal-footer"}),o=i.createEl("button",{text:"Cancel"});o.onclick=()=>this.close();let l=i.createEl("button",{text:"Save",cls:"mod-cta"});l.onclick=async()=>{l.setText("Saving\u2026"),l.disabled=!0;try{await Bi(this.app.vault,this.plugin.settings.fleetFolder,this.agent.name,this.edit),await this.plugin.refreshFromVault(),this.close(),new D.Notice("Saved."),this.onSaved()}catch(c){let d=c instanceof Error?c.message:String(c);new D.Notice(`Failed to save: ${d}`),l.setText("Save"),l.disabled=!1}}}onClose(){this.contentEl.empty()}};function ud(a){return a.type==="slack",a.botToken}function hd(a){return a.length<=10?"***":`${a.slice(0,6)}\u2026${a.slice(-4)}`}var mr=require("crypto");function Ge(a,e,t,s,n,r,i,o){return Ge.fromTZ(Ge.tp(a,e,t,s,n,r,i),o)}Ge.fromTZISO=(a,e,t)=>Ge.fromTZ(pd(a,e),t);Ge.fromTZ=function(a,e){let t=new Date(Date.UTC(a.y,a.m-1,a.d,a.h,a.i,a.s)),s=Za(a.tz,t),n=new Date(t.getTime()-s),r=Za(a.tz,n);if(r-s===0)return n;{let i=new Date(t.getTime()-r),o=Za(a.tz,i);if(o-r===0)return i;if(!e&&o-r>0)return i;if(e)throw new Error("Invalid date passed to fromTZ()");return n}};Ge.toTZ=function(a,e){let t=a.toLocaleString("en-US",{timeZone:e}).replace(/[\u202f]/," "),s=new Date(t);return{y:s.getFullYear(),m:s.getMonth()+1,d:s.getDate(),h:s.getHours(),i:s.getMinutes(),s:s.getSeconds(),tz:e}};Ge.tp=(a,e,t,s,n,r,i)=>({y:a,m:e,d:t,h:s,i:n,s:r,tz:i});function Za(a,e=new Date){let t=e.toLocaleString("en-US",{timeZone:a,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],s=e.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${s} GMT`)-Date.parse(`${s} ${t}`)}function pd(a,e){let t=new Date(Date.parse(a));if(isNaN(t))throw new Error("minitz: Invalid ISO8601 passed to parser.");let s=a.substring(9);return a.includes("Z")||s.includes("-")||s.includes("+")?Ge.tp(t.getUTCFullYear(),t.getUTCMonth()+1,t.getUTCDate(),t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds(),"Etc/UTC"):Ge.tp(t.getFullYear(),t.getMonth()+1,t.getDate(),t.getHours(),t.getMinutes(),t.getSeconds(),e)}Ge.minitz=Ge;function md(a){if(a===void 0&&(a={}),delete a.name,a.legacyMode=a.legacyMode===void 0?!0:a.legacyMode,a.paused=a.paused===void 0?!1:a.paused,a.maxRuns=a.maxRuns===void 0?1/0:a.maxRuns,a.catch=a.catch===void 0?!1:a.catch,a.interval=a.interval===void 0?0:parseInt(a.interval,10),a.utcOffset=a.utcOffset===void 0?void 0:parseInt(a.utcOffset,10),a.unref=a.unref===void 0?!1:a.unref,a.startAt&&(a.startAt=new Te(a.startAt,a.timezone)),a.stopAt&&(a.stopAt=new Te(a.stopAt,a.timezone)),a.interval!==null){if(isNaN(a.interval))throw new Error("CronOptions: Supplied value for interval is not a number");if(a.interval<0)throw new Error("CronOptions: Supplied value for interval can not be negative")}if(a.utcOffset!==void 0){if(isNaN(a.utcOffset))throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");if(a.utcOffset<-870||a.utcOffset>870)throw new Error("CronOptions: utcOffset out of bounds.");if(a.utcOffset!==void 0&&a.timezone)throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}if(a.unref!==!0&&a.unref!==!1)throw new Error("CronOptions: Unref should be either true, false or undefined(false).");return a}var er=32,$s=31|er,ji=[1,2,4,8,16];function Je(a,e){this.pattern=a,this.timezone=e,this.second=Array(60).fill(0),this.minute=Array(60).fill(0),this.hour=Array(24).fill(0),this.day=Array(31).fill(0),this.month=Array(12).fill(0),this.dayOfWeek=Array(7).fill(0),this.lastDayOfMonth=!1,this.starDOM=!1,this.starDOW=!1,this.parse()}Je.prototype.parse=function(){if(!(typeof this.pattern=="string"||this.pattern.constructor===String))throw new TypeError("CronPattern: Pattern has to be of type string.");this.pattern.indexOf("@")>=0&&(this.pattern=this.handleNicknames(this.pattern).trim());let a=this.pattern.replace(/\s+/g," ").split(" ");if(a.length<5||a.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exactly five or six space separated parts are required.");if(a.length===5&&a.unshift("0"),a[3].indexOf("L")>=0&&(a[3]=a[3].replace("L",""),this.lastDayOfMonth=!0),a[3]=="*"&&(this.starDOM=!0),a[4].length>=3&&(a[4]=this.replaceAlphaMonths(a[4])),a[5].length>=3&&(a[5]=this.replaceAlphaDays(a[5])),a[5]=="*"&&(this.starDOW=!0),this.pattern.indexOf("?")>=0){let e=new Te(new Date,this.timezone).getDate(!0);a[0]=a[0].replace("?",e.getSeconds()),a[1]=a[1].replace("?",e.getMinutes()),a[2]=a[2].replace("?",e.getHours()),this.starDOM||(a[3]=a[3].replace("?",e.getDate())),a[4]=a[4].replace("?",e.getMonth()+1),this.starDOW||(a[5]=a[5].replace("?",e.getDay()))}this.throwAtIllegalCharacters(a),this.partToArray("second",a[0],0,1),this.partToArray("minute",a[1],0,1),this.partToArray("hour",a[2],0,1),this.partToArray("day",a[3],-1,1),this.partToArray("month",a[4],-1,1),this.partToArray("dayOfWeek",a[5],0,$s),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])};Je.prototype.partToArray=function(a,e,t,s){let n=this[a],r=a==="day"&&this.lastDayOfMonth;if(e===""&&!r)throw new TypeError("CronPattern: configuration entry "+a+" ("+e+") is empty, check for trailing spaces.");if(e==="*")return n.fill(s);let i=e.split(",");if(i.length>1)for(let o=0;o<i.length;o++)this.partToArray(a,i[o],t,s);else e.indexOf("-")!==-1&&e.indexOf("/")!==-1?this.handleRangeWithStepping(e,a,t,s):e.indexOf("-")!==-1?this.handleRange(e,a,t,s):e.indexOf("/")!==-1?this.handleStepping(e,a,t,s):e!==""&&this.handleNumber(e,a,t,s)};Je.prototype.throwAtIllegalCharacters=function(a){for(let e=0;e<a.length;e++)if((e===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(a[e]))throw new TypeError("CronPattern: configuration entry "+e+" ("+a[e]+") contains illegal characters.")};Je.prototype.handleNumber=function(a,e,t,s){let n=this.extractNth(a,e),r=parseInt(n[0],10)+t;if(isNaN(r))throw new TypeError("CronPattern: "+e+" is not a number: '"+a+"'");this.setPart(e,r,n[1]||s)};Je.prototype.setPart=function(a,e,t){if(!Object.prototype.hasOwnProperty.call(this,a))throw new TypeError("CronPattern: Invalid part specified: "+a);if(a==="dayOfWeek"){if(e===7&&(e=0),(e<0||e>6)&&e!=="L")throw new RangeError("CronPattern: Invalid value for dayOfWeek: "+e);this.setNthWeekdayOfMonth(e,t);return}if(a==="second"||a==="minute"){if(e<0||e>=60)throw new RangeError("CronPattern: Invalid value for "+a+": "+e)}else if(a==="hour"){if(e<0||e>=24)throw new RangeError("CronPattern: Invalid value for "+a+": "+e)}else if(a==="day"){if(e<0||e>=31)throw new RangeError("CronPattern: Invalid value for "+a+": "+e)}else if(a==="month"&&(e<0||e>=12))throw new RangeError("CronPattern: Invalid value for "+a+": "+e);this[a][e]=t};Je.prototype.handleRangeWithStepping=function(a,e,t,s){let n=this.extractNth(a,e),r=n[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(r===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+a+"'");let[,i,o,l]=r;if(i=parseInt(i,10)+t,o=parseInt(o,10)+t,l=parseInt(l,10),isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(l))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(l===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(l>this[e].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[e].length+")");if(i>o)throw new TypeError("CronPattern: From value is larger than to value: '"+a+"'");for(let c=i;c<=o;c+=l)this.setPart(e,c,n[1]||s)};Je.prototype.extractNth=function(a,e){let t=a,s;if(t.includes("#")){if(e!=="dayOfWeek")throw new Error("CronPattern: nth (#) only allowed in day-of-week field");s=t.split("#")[1],t=t.split("#")[0]}return[t,s]};Je.prototype.handleRange=function(a,e,t,s){let n=this.extractNth(a,e),r=n[0].split("-");if(r.length!==2)throw new TypeError("CronPattern: Syntax error, illegal range: '"+a+"'");let i=parseInt(r[0],10)+t,o=parseInt(r[1],10)+t;if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(i>o)throw new TypeError("CronPattern: From value is larger than to value: '"+a+"'");for(let l=i;l<=o;l++)this.setPart(e,l,n[1]||s)};Je.prototype.handleStepping=function(a,e,t,s){let n=this.extractNth(a,e),r=n[0].split("/");if(r.length!==2)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+a+"'");let i=0;r[0]!=="*"&&(i=parseInt(r[0],10)+t);let o=parseInt(r[1],10);if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(o===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(o>this[e].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[e].length+")");for(let l=i;l<this[e].length;l+=o)this.setPart(e,l,n[1]||s)};Je.prototype.replaceAlphaDays=function(a){return a.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};Je.prototype.replaceAlphaMonths=function(a){return a.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};Je.prototype.handleNicknames=function(a){let e=a.trim().toLowerCase();return e==="@yearly"||e==="@annually"?"0 0 1 1 *":e==="@monthly"?"0 0 1 * *":e==="@weekly"?"0 0 * * 0":e==="@daily"?"0 0 * * *":e==="@hourly"?"0 * * * *":a};Je.prototype.setNthWeekdayOfMonth=function(a,e){if(e==="L")this.dayOfWeek[a]=this.dayOfWeek[a]|er;else if(e<6&&e>0)this.dayOfWeek[a]=this.dayOfWeek[a]|ji[e-1];else if(e===$s)this.dayOfWeek[a]=$s;else throw new TypeError(`CronPattern: nth weekday of of range, should be 1-5 or L. Value: ${e}`)};var Hi=[31,28,31,30,31,30,31,31,30,31,30,31],Dt=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function Te(a,e){if(this.tz=e,a&&a instanceof Date)if(!isNaN(a))this.fromDate(a);else throw new TypeError("CronDate: Invalid date passed to CronDate constructor");else if(a===void 0)this.fromDate(new Date);else if(a&&typeof a=="string")this.fromString(a);else if(a instanceof Te)this.fromCronDate(a);else throw new TypeError("CronDate: Invalid type ("+typeof a+") passed to CronDate constructor")}Te.prototype.isNthWeekdayOfMonth=function(a,e,t,s){let r=new Date(Date.UTC(a,e,t)).getUTCDay(),i=0;for(let o=1;o<=t;o++)new Date(Date.UTC(a,e,o)).getUTCDay()===r&&i++;if(s&$s&&ji[i-1]&s)return!0;if(s&er){let o=new Date(Date.UTC(a,e+1,0)).getUTCDate();for(let l=t+1;l<=o;l++)if(new Date(Date.UTC(a,e,l)).getUTCDay()===r)return!1;return!0}return!1};Te.prototype.fromDate=function(a){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=a.getUTCMilliseconds(),this.second=a.getUTCSeconds(),this.minute=a.getUTCMinutes()+this.tz,this.hour=a.getUTCHours(),this.day=a.getUTCDate(),this.month=a.getUTCMonth(),this.year=a.getUTCFullYear(),this.apply();else{let e=Ge.toTZ(a,this.tz);this.ms=a.getMilliseconds(),this.second=e.s,this.minute=e.i,this.hour=e.h,this.day=e.d,this.month=e.m-1,this.year=e.y}else this.ms=a.getMilliseconds(),this.second=a.getSeconds(),this.minute=a.getMinutes(),this.hour=a.getHours(),this.day=a.getDate(),this.month=a.getMonth(),this.year=a.getFullYear()};Te.prototype.fromCronDate=function(a){this.tz=a.tz,this.year=a.year,this.month=a.month,this.day=a.day,this.hour=a.hour,this.minute=a.minute,this.second=a.second,this.ms=a.ms};Te.prototype.apply=function(){if(this.month>11||this.day>Hi[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let a=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return this.ms=a.getUTCMilliseconds(),this.second=a.getUTCSeconds(),this.minute=a.getUTCMinutes(),this.hour=a.getUTCHours(),this.day=a.getUTCDate(),this.month=a.getUTCMonth(),this.year=a.getUTCFullYear(),!0}else return!1};Te.prototype.fromString=function(a){if(typeof this.tz=="number"){let e=Ge.fromTZISO(a);this.ms=e.getUTCMilliseconds(),this.second=e.getUTCSeconds(),this.minute=e.getUTCMinutes(),this.hour=e.getUTCHours(),this.day=e.getUTCDate(),this.month=e.getUTCMonth(),this.year=e.getUTCFullYear(),this.apply()}else return this.fromDate(Ge.fromTZISO(a,this.tz))};Te.prototype.findNext=function(a,e,t,s){let n=this[e],r;t.lastDayOfMonth&&(this.month!==1?r=Hi[this.month]:r=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let i=!t.starDOW&&e=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let o=this[e]+s;o<t[e].length;o++){let l=t[e][o];if(e==="day"&&t.lastDayOfMonth&&o-s==r&&(l=!0),e==="day"&&!t.starDOW){let c=t.dayOfWeek[(i+(o-s-1))%7];if(c&&c&$s)c=this.isNthWeekdayOfMonth(this.year,this.month,o-s,c);else if(c)throw new Error(`CronDate: Invalid value for dayOfWeek encountered. ${c}`);a.legacyMode&&!t.starDOM?l=l||c:l=l&&c}if(l)return this[e]=o-s,n!==this[e]?2:1}return 3};Te.prototype.recurse=function(a,e,t){let s=this.findNext(e,Dt[t][0],a,Dt[t][2]);if(s>1){let n=t+1;for(;n<Dt.length;)this[Dt[n][0]]=-Dt[n][2],n++;if(s===3)return this[Dt[t][1]]++,this[Dt[t][0]]=-Dt[t][2],this.apply(),this.recurse(a,e,0);if(this.apply())return this.recurse(a,e,t-1)}return t+=1,t>=Dt.length?this:this.year>=3e3?null:this.recurse(a,e,t)};Te.prototype.increment=function(a,e,t){return this.second+=e.interval>1&&t?e.interval:1,this.ms=0,this.apply(),this.recurse(a,e,0)};Te.prototype.getDate=function(a){return a||this.tz===void 0?new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms):typeof this.tz=="number"?new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms)):Ge(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)};Te.prototype.getTime=function(){return this.getDate().getTime()};function $n(a){return Object.prototype.toString.call(a)==="[object Function]"||typeof a=="function"||a instanceof Function}function fd(a){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(a):a&&typeof a.unref<"u"&&a.unref()}var $i=30*1e3,js=[];function ie(a,e,t){if(!(this instanceof ie))return new ie(a,e,t);let s,n;if($n(e))n=e;else if(typeof e=="object")s=e;else if(e!==void 0)throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if($n(t))n=t;else if(typeof t=="object")s=t;else if(t!==void 0)throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=s?s.name:void 0,this.options=md(s),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:s?s.maxRuns:void 0,paused:s?s.paused:!1,pattern:void 0},a&&(a instanceof Date||typeof a=="string"&&a.indexOf(":")>0)?this._states.once=new Te(a,this.options.timezone||this.options.utcOffset):this._states.pattern=new Je(a,this.options.timezone),this.name){if(js.find(i=>i.name===this.name))throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");js.push(this)}return n!==void 0&&(this.fn=n,this.schedule()),this}ie.prototype.nextRun=function(a){let e=this._next(a);return e?e.getDate():null};ie.prototype.nextRuns=function(a,e){a>this._states.maxRuns&&(a=this._states.maxRuns);let t=[],s=e||this._states.currentRun;for(;a--&&(s=this.nextRun(s));)t.push(s);return t};ie.prototype.getPattern=function(){return this._states.pattern?this._states.pattern.pattern:void 0};ie.prototype.isRunning=function(){let a=this.nextRun(this._states.currentRun),e=!this._states.paused,t=this.fn!==void 0,s=!this._states.kill;return e&&t&&s&&a!==null};ie.prototype.isStopped=function(){return this._states.kill};ie.prototype.isBusy=function(){return this._states.blocking};ie.prototype.currentRun=function(){return this._states.currentRun?this._states.currentRun.getDate():null};ie.prototype.previousRun=function(){return this._states.previousRun?this._states.previousRun.getDate():null};ie.prototype.msToNext=function(a){a=a||new Date;let e=this._next(a);return e?e.getTime()-a.getTime():null};ie.prototype.stop=function(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let a=js.indexOf(this);a>=0&&js.splice(a,1)};ie.prototype.pause=function(){return this._states.paused=!0,!this._states.kill};ie.prototype.resume=function(){return this._states.paused=!1,!this._states.kill};ie.prototype.schedule=function(a){if(a&&this.fn)throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");a&&(this.fn=a);let e=this.msToNext(),t=this.nextRun(this._states.currentRun);return e==null||isNaN(e)||t===null?this:(e>$i&&(e=$i),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(t),e),this._states.currentTimeout&&this.options.unref&&fd(this._states.currentTimeout),this)};ie.prototype._trigger=async function(a){if(this._states.blocking=!0,this._states.currentRun=new Te(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{await this.fn(this,this.options.context)}catch(e){$n(this.options.catch)&&this.options.catch(e,this)}else await this.fn(this,this.options.context);this._states.previousRun=new Te(a,this.options.timezone||this.options.utcOffset),this._states.blocking=!1};ie.prototype.trigger=async function(){await this._trigger()};ie.prototype._checkTrigger=function(a){let e=new Date,t=!this._states.paused&&e.getTime()>=a,s=this._states.blocking&&this.options.protect;t&&!s?(this._states.maxRuns--,this._trigger()):t&&s&&$n(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()};ie.prototype._next=function(a){let e=!!(a||this._states.currentRun),t=!1;!a&&this.options.startAt&&this.options.interval&&([a,e]=this._calculatePreviousRun(a,e),t=!a),a=new Te(a,this.options.timezone||this.options.utcOffset),this.options.startAt&&a&&a.getTime()<this.options.startAt.getTime()&&(a=this.options.startAt);let s=this._states.once||new Te(a,this.options.timezone||this.options.utcOffset);return!t&&s!==this._states.once&&(s=s.increment(this._states.pattern,this.options,e)),this._states.once&&this._states.once.getTime()<=a.getTime()||s===null||this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&s.getTime()>=this.options.stopAt.getTime()?null:s};ie.prototype._calculatePreviousRun=function(a,e){let t=new Te(void 0,this.options.timezone||this.options.utcOffset);if(this.options.startAt.getTime()<=t.getTime()){a=this.options.startAt;let s=a.getTime()+this.options.interval*1e3;for(;s<=t.getTime();)a=new Te(a,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),s=a.getTime()+this.options.interval*1e3;e=!0}return[a,e]};ie.Cron=ie;ie.scheduledJobs=js;var xo=require("obsidian");var mo=require("crypto");var rt=require("fs"),tr=require("path");function gd(a){return`mcp__${a.replace(/[\s.]+/g,"_")}`}function jn(a,e,t={}){let s=e.permissionRules.allow.length>0||e.permissionRules.deny.length>0,n=e.permissionMode?.trim(),r=!!n&&n!=="default",i=t.mcpAllowServers??[],o=i.length>0;if(!(s||r||o))return null;let c=(0,tr.join)(a,".claude"),d=(0,tr.join)(c,"settings.local.json");(0,rt.existsSync)(c)||(0,rt.mkdirSync)(c,{recursive:!0});let u=null;if((0,rt.existsSync)(d))try{u=(0,rt.readFileSync)(d,"utf-8")}catch{u=null}let h={};if(r&&(h.defaultMode=n),s||o){let p=[...e.permissionRules.allow];for(let m of i)p.push(gd(m));h.permissions={allow:p,deny:e.permissionRules.deny}}return(0,rt.writeFileSync)(d,JSON.stringify(h,null,2)+`
|
|
11776
|
+
`,"utf-8"),{path:d,backupContent:u}}function Zt(a){if(a){if(a.backupContent!==null)try{(0,rt.writeFileSync)(a.path,a.backupContent,"utf-8");return}catch(e){console.warn(`Agent Fleet: failed to restore the previous ${a.path} (${e instanceof Error?e.message:String(e)}); deleting the temporary agent settings file instead so it doesn't affect later runs.`)}try{(0,rt.existsSync)(a.path)&&(0,rt.unlinkSync)(a.path)}catch(e){console.warn(`Agent Fleet: failed to remove the temporary agent settings file at ${a.path} (${e instanceof Error?e.message:String(e)}). Stale agent permissions may leak into the next Claude run in this directory \u2014 delete it manually.`)}}}function es(a){try{return JSON.parse(a)}catch{return}}var Wi=200;function Hs(a,e,t){let s=e.length>Wi?`${e.slice(0,Wi)}\u2026`:e,n=t instanceof Error?t.message:t!==void 0?String(t):"no parseable JSON found";console.warn(`Agent Fleet: ${a} \u2014 ${n}. Output begins: ${s}`)}function qi(a,e){try{return JSON.parse(e)}catch(t){Hs(a,e,t);return}}function zi(a){if(typeof a=="string")return a;if(Array.isArray(a))return a.map(t=>{if(typeof t=="string")return t;if(t&&typeof t=="object"&&"text"in t){let s=t.text;if(typeof s=="string")return s}return""}).filter(Boolean).join(`
|
|
11777
|
+
`);if(a&&typeof a=="object"){for(let e of["output","result","text","message"])if(e in a)return zi(a[e])}}function sr(a,e=[]){if(Array.isArray(a)){for(let i of a)sr(i,e);return e}if(!a||typeof a!="object")return e;let t=a,s=typeof t.tool_name=="string"&&t.tool_name||typeof t.tool=="string"&&t.tool||typeof t.name=="string"&&t.name,n=typeof t.command=="string"?t.command:typeof t.input=="string"?t.input:typeof t.cmd=="string"?t.cmd:void 0,r=typeof t.reason=="string"?t.reason:void 0;s&&["tool_use","tool","name","tool_name"].some(i=>i in t)&&e.push({tool:s,command:n,reason:r});for(let i of Object.values(t))sr(i,e);return e}function Gi(a){if(!a||typeof a!="object")return;let e=a,t=e.usage;if(t&&typeof t=="object"){let n=typeof t.input_tokens=="number"?t.input_tokens:0,r=typeof t.output_tokens=="number"?t.output_tokens:0,i=typeof t.cache_creation_input_tokens=="number"?t.cache_creation_input_tokens:0,o=typeof t.cache_read_input_tokens=="number"?t.cache_read_input_tokens:0,l=n+r+i+o;if(l>0)return l}let s=e.modelUsage;if(s&&typeof s=="object"){let n=0;for(let r of Object.values(s)){if(!r||typeof r!="object")continue;let i=r;n+=typeof i.inputTokens=="number"?i.inputTokens:0,n+=typeof i.outputTokens=="number"?i.outputTokens:0,n+=typeof i.cacheReadInputTokens=="number"?i.cacheReadInputTokens:0,n+=typeof i.cacheCreationInputTokens=="number"?i.cacheCreationInputTokens:0}if(n>0)return n}for(let n of["tokens_used","total_tokens","totalTokens"])if(typeof e[n]=="number")return e[n];for(let n of Object.values(e)){let r=Gi(n);if(typeof r=="number")return r}}function Vi(a){if(!a||typeof a!="object")return;let e=a;if(typeof e.total_cost_usd=="number")return e.total_cost_usd;for(let t of Object.values(e)){let s=Vi(t);if(typeof s=="number")return s}}function nr(a){if(!a||typeof a!="object")return;let e=a;if(e.type==="result"&&typeof e.result=="string"&&e.result.trim())return e.result}function Hn(a){if(!a||typeof a!="object")return;let e=a;if(e.modelUsage&&typeof e.modelUsage=="object"){let s=Object.keys(e.modelUsage);if(s.length>0&&s[0])return s[0]}let t=e.message;if(t&&typeof t.model=="string"&&t.model)return t.model;if(typeof e.model=="string"&&e.model)return e.model;for(let s of Object.values(e)){let n=Hn(s);if(n)return n}}function yd(a){return/^gpt-|codex/i.test(a.trim())}var Yi={id:"claude-code",label:"Claude Code",cliPath(a){return a.claudeCliPath},buildExec(a){let e=["-p","--output-format",a.streaming?"stream-json":"json"];a.streaming&&e.push("--verbose");let t=a.modelSource==="settings"&&yd(a.model);a.model&&!t&&e.push("--model",a.model),a.effort&&e.push("--effort",a.effort);let s=a.agent.permissionMode?.trim();return s&&s!=="default"?e.push("--permission-mode",s):e.push("--permission-mode","bypassPermissions"),Promise.resolve({cliPath:a.settings.claudeCliPath,args:e,stdinPayload:a.prompt})},parseExecOutput(a,e,t){let s=a.trim(),n;if(t){let l=re(s);for(let c=l.length-1;c>=0;c--){let d=l[c]?.trim();if(!d)continue;let u=es(d);if(u&&typeof u=="object"){n=u;break}}n===void 0&&s&&Hs("Claude Code stream-json output contained no parseable JSON event",s)}else(s.startsWith("{")||s.startsWith("["))&&(n=qi("Claude Code JSON output failed to parse",s));let r=zi(n)??"";if(!r&&t){let l=[];for(let c of re(s)){let d=c.trim();if(!d)continue;let u=es(d);if(!(!u||typeof u!="object"))if(u.type==="assistant"&&u.message?.content)for(let h of u.message.content)h.type==="text"&&h.text&&l.push(h.text);else u.type==="result"&&typeof u.result=="string"&&l.push(u.result)}r=l.join(`
|
|
11778
|
+
`).trim()}r||(r=e.trim()||"(no output)");let i=Hn(n),o=nr(n);if((!i||!o)&&t)for(let l of re(s)){let c=l.trim();if(!c)continue;let d=es(c);if(d!==void 0){if(!i){let u=Hn(d);u&&(i=u)}if(!o){let u=nr(d);u&&(o=u)}if(i&&o)break}}return{outputText:r,finalResult:o,tokensUsed:Gi(n),costUsd:Vi(n),toolsUsed:sr(n),concreteModel:i,rawJson:n}},extractStreamChunk(a){let e=a.trim();if(!e)return null;let t=es(e);if(!t||typeof t!="object"||Array.isArray(t))return null;let s=t,n=s.type;if(n==="assistant"){let r=s.message;if(r?.content&&Array.isArray(r.content)){let i=[];for(let o of r.content)if(o.type==="text"&&typeof o.text=="string")i.push(o.text);else if(o.type==="tool_use"){let l=String(o.name??"tool"),c=o.input,d=c?.command??c?.content??"";i.push(`
|
|
11779
|
+
\u25B8 ${l}${d?`: ${String(d).slice(0,200)}`:""}
|
|
11780
|
+
`)}if(i.length>0)return i.join("")}}if(n==="result"){let r=typeof s.result=="string"?s.result:null;if(r)return`
|
|
11781
|
+
${r}`}return null},setupPermissions(a,e,t,s){let n=jn(a,e,{mcpAllowServers:s?.mcpAllowServers});return n?Promise.resolve({restore:()=>Zt(n)}):Promise.resolve(null)}};var se=require("fs"),ir=require("crypto"),qs=require("os"),Xe=require("path");var vd=/^[A-Z][A-Za-z]*$/;function wd(a){let e=a.trim();if(!e)return{error:"empty Bash() matches every command \u2014 use the read-only sandbox instead"};let t=e.split(/\s+/).filter(Boolean),s=[];for(let n=0;n<t.length;n++){let r=t[n],i=n===t.length-1;if(r==="*"){if(i)continue;return{error:"a wildcard in the middle of a command can't be expressed as a prefix rule"}}if(r.includes("*"))return{error:"embedded wildcards aren't supported (execpolicy matches argv prefixes only)"};s.push(r)}return s.length===0?{error:"a bare wildcard matches every command \u2014 use the read-only sandbox instead"}:{tokens:s}}function bd(a,e){return`prefix_rule(pattern=[${a.map(s=>JSON.stringify(s)).join(", ")}], decision="${e}", justification="agent-fleet")`}function kd(a){let e=[],t=[],s=(r,i)=>{let o=r.trim();if(!o||o.startsWith("mcp__"))return;let l=o.match(/^Bash\((.*)\)$/s);if(!l){t.push({rule:o,reason:vd.test(o)?"tool-name rules are governed by the sandbox, not execpolicy":"not a Bash(...) command pattern"});return}let c=wd(l[1]);if("error"in c){t.push({rule:o,reason:c.error});return}e.push(bd(c.tokens,i))};for(let r of a.permissionRules.deny)s(r,"forbidden");for(let r of a.permissionRules.allow)s(r,"allow");return e.length===0?{rulesText:null,dropped:t,emitted:0}:{rulesText:`${`# Generated by Agent Fleet for agent "${a.name}". Do not edit \u2014 regenerated each run.
|
|
11781
11782
|
# Source: this agent's permissionRules (allow/deny), translated to Codex execpolicy.
|
|
11782
|
-
`}${
|
|
11783
|
+
`}${e.join(`
|
|
11783
11784
|
`)}
|
|
11784
|
-
`,dropped:
|
|
11785
|
-
`,"utf-8"),await
|
|
11785
|
+
`,dropped:t,emitted:e.length}}function xd(){let a=process.env.CODEX_HOME?.trim();return a||(0,Xe.join)((0,qs.homedir)(),".codex")}var Ji=(0,Xe.join)((0,qs.tmpdir)(),"agent-fleet-codex");function Sd(a){let e=a.name.replace(/[^A-Za-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")||"agent",t=(0,ir.createHash)("sha1").update(a.filePath).digest("hex").slice(0,8);return(0,Xe.join)(Ji,`${e}-${t}`)}function Cd(a,e){let t=`${a}.${process.pid}.${Date.now()}.tmp`;(0,se.writeFileSync)(t,e,"utf-8"),(0,se.renameSync)(t,a)}function Td(a,e){try{let t=(0,se.lstatSync)(e);if(t.isSymbolicLink()){try{if((0,se.readlinkSync)(e)===a)return}catch{}(0,se.unlinkSync)(e)}else t.isDirectory()?(0,se.rmSync)(e,{recursive:!0,force:!0}):(0,se.unlinkSync)(e)}catch{}(0,se.symlinkSync)(a,e)}function _d(a,e,t=xd()){if(!(0,se.existsSync)(t))return null;let s=Sd(a);(0,se.mkdirSync)(s,{recursive:!0});for(let o of(0,se.readdirSync)(t))o!=="rules"&&Td((0,Xe.join)(t,o),(0,Xe.join)(s,o));let n=(0,Xe.join)(s,"rules");(0,se.mkdirSync)(n,{recursive:!0});let r=(0,Xe.join)(t,"rules");if((0,se.existsSync)(r)){for(let o of(0,se.readdirSync)(r))if(o.endsWith(".rules"))try{(0,se.copyFileSync)((0,Xe.join)(r,o),(0,Xe.join)(n,`user-${o}`))}catch(l){console.warn(`Agent Fleet: couldn't copy the Codex rules file ${(0,Xe.join)(r,o)} into agent "${a.name}"'s permission overlay (${l instanceof Error?l.message:String(l)}); its rules will NOT apply to this agent's runs.`)}}let i=(0,Xe.join)(n,"agent-fleet.rules");return Cd(i,e),{codexHome:s,rulesPath:i}}function Xi(){try{(0,se.rmSync)(Ji,{recursive:!0,force:!0})}catch{}}var ar=new Map,rr=new Map;function Qi(){ar.clear(),rr.clear()}function Zi(a,e,t){return new Promise(s=>{let n=!1,r=i=>{n||(n=!0,s(i))};try{let i=wt(a,["execpolicy","check","--rules",e,...t]),o=window.setTimeout(()=>{try{i.kill()}catch{}r(null)},8e3);i.on("error",()=>{window.clearTimeout(o),r(null)}),i.on("close",l=>{window.clearTimeout(o),r(l)})}catch{r(null)}})}function Ad(a){let e=ar.get(a);if(e)return e;let t=(async()=>{let s=null;try{s=(0,se.mkdtempSync)((0,Xe.join)((0,qs.tmpdir)(),"af-codex-probe-"));let n=(0,Xe.join)(s,"probe.rules");return(0,se.writeFileSync)(n,`prefix_rule(pattern=["ls"], decision="allow")
|
|
11786
|
+
`,"utf-8"),await Zi(a,n,["ls"])===0}catch{return!1}finally{if(s)try{(0,se.rmSync)(s,{recursive:!0,force:!0})}catch{}}})();return ar.set(a,t),t}async function Pd(a,e,t){let s=`${a}:${(0,ir.createHash)("sha1").update(t).digest("hex")}`,n=rr.get(s);if(n!==void 0)return n;let i=await Zi(a,e,["true"])===0;return rr.set(s,i),i}var Ki=new Set;function Ws(a,e){Ki.has(a)||(Ki.add(a),console.warn(`Agent Fleet: ${e}`))}async function eo(a,e){if(!(a.permissionRules.allow.length>0||a.permissionRules.deny.length>0))return null;let{rulesText:s,dropped:n}=kd(a);if(n.length>0&&Ws(`dropped:${a.name}:${n.map(c=>c.rule).join("|")}`,`agent "${a.name}": ${n.length} permission rule(s) can't be enforced by Codex and were ignored \u2014 ${n.map(c=>`"${c.rule}" (${c.reason})`).join("; ")}. File/network access is governed by the sandbox (Permission Mode).`),!s)return null;let r=e.codexCliPath;if(!await Ad(r))return Ws(`unsupported:${r}`,`this Codex build doesn't support execpolicy rules; agent "${a.name}" runs with sandbox-only enforcement. Update Codex to enforce command allow/deny rules.`),null;let o;try{o=_d(a,s)}catch(c){return Ws(`overlay-fail:${a.name}`,`couldn't build the Codex permission overlay for agent "${a.name}" (${c instanceof Error?c.message:String(c)}); falling back to sandbox-only (symlinks may be unavailable on this platform).`),null}return o?await Pd(r,o.rulesPath,s)?{restore:()=>{},env:{CODEX_HOME:o.codexHome}}:(Ws(`invalid-rules:${a.name}`,`generated Codex rules for agent "${a.name}" failed validation; falling back to sandbox-only.`),null):(Ws("no-codex-home",`Codex home (~/.codex) not found; agent "${a.name}" runs with sandbox-only enforcement. Run \`codex login\` first.`),null)}function Ed(a){let e=a.trim();return/^(opus|sonnet|haiku|opusplan)$/i.test(e)||/claude|anthropic/i.test(e)}function Dd(a){let e=a.trim().toLowerCase();return e?e==="max"?"xhigh":["low","medium","high","xhigh"].includes(e)?e:"":""}function Rd(a){switch((a??"").trim()){case"plan":case"read-only":return["--sandbox","read-only"];case"acceptEdits":case"default":case"workspace-write":return["--sandbox","workspace-write"];case"danger-full-access":return["--sandbox","danger-full-access"];default:return["--dangerously-bypass-approvals-and-sandbox"]}}function Id(a){let e=["exec","--json","--skip-git-repo-check"],t=a.modelSource==="settings"&&Ed(a.model);a.model&&!t&&e.push("-m",a.model);let s=Dd(a.effort);return s&&e.push("-c",`model_reasoning_effort="${s}"`),e.push(...Rd(a.agent.permissionMode)),a.resumeSessionId&&e.push("resume",a.resumeSessionId),e.push("-"),{args:e,stdinPayload:a.prompt}}function to(a){let e=a.trim();if(!e)return null;let t=es(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}function Wn(a){let e=a.item;return e&&typeof e=="object"?e:null}function or(a){let e=typeof a.type=="string"?a.type:"";if(e==="command_execution")return{tool:"shell",command:typeof a.command=="string"?a.command:void 0};if(e==="mcp_tool_call"){let t=typeof a.server=="string"?a.server:"mcp",s=typeof a.tool=="string"?a.tool:"tool";return{tool:`mcp__${t}__${s}`}}return e==="web_search"?{tool:"web_search",command:typeof a.query=="string"?a.query:void 0}:e==="file_change"?{tool:"file_change",command:(Array.isArray(a.changes)?a.changes:[]).map(n=>`${typeof n.kind=="string"?n.kind:"update"} ${typeof n.path=="string"?n.path:""}`.trim()).filter(Boolean).join(", ")||void 0}:null}function so(a){let e=a.usage;if(!e||typeof e!="object")return 0;let t=typeof e.input_tokens=="number"?e.input_tokens:0,s=typeof e.output_tokens=="number"?e.output_tokens:0;return t+s}function Md(a){let e=a.usage;return!e||typeof e!="object"?0:typeof e.input_tokens=="number"?e.input_tokens:0}function lr(){return{emittedTextLengths:new Map}}function no(a,e){let t=typeof a.type=="string"?a.type:"",s=[];if(t==="thread.started"&&typeof a.thread_id=="string"&&a.thread_id)return s.push({kind:"session",sessionId:a.thread_id}),s;if(t==="turn.completed")return s.push({kind:"usage",contextTokens:Md(a),totalTokens:so(a)}),s;if(t==="turn.failed"){let n=a.error,r=n&&typeof n.message=="string"?n.message:"turn failed";return s.push({kind:"turn-failed",message:r}),s}if(t==="error"){let n=typeof a.message=="string"?a.message:"stream error";return s.push({kind:"error",message:n}),s}if(t==="item.started"||t==="item.updated"||t==="item.completed"){let n=Wn(a);if(!n)return s;let r=typeof n.type=="string"?n.type:"";if(r==="agent_message"){let i=typeof n.text=="string"?n.text:"",o=typeof n.id=="string"?n.id:"__single__",l=e.emittedTextLengths.get(o)??0;return i.length>l&&(s.push({kind:"text",text:i.slice(l)}),e.emittedTextLengths.set(o,i.length)),s}if(r==="error"){let i=typeof n.message=="string"?n.message:"item error";return s.push({kind:"error",message:i}),s}if(t==="item.started"){let i=or(n);i&&s.push({kind:"tool",toolName:i.tool,command:i.command})}return s}return s}var zs={id:"codex",label:"Codex",cliPath(a){return a.codexCliPath},buildExec(a){let{args:e,stdinPayload:t}=Id(a);return Promise.resolve({cliPath:a.settings.codexCliPath,args:e,stdinPayload:t})},parseExecOutput(a,e,t){let s=[],n=[],r=[],i=0,o,l,c=!1;for(let h of re(a)){let p=to(h);if(!p)continue;c=!0;let m=typeof p.type=="string"?p.type:"";if(m==="thread.started"&&typeof p.thread_id=="string")o=p.thread_id;else if(m==="turn.completed")i+=so(p),l=p;else if(m==="turn.failed"){let f=p.error;r.push(f&&typeof f.message=="string"?f.message:"turn failed")}else if(m==="error")r.push(typeof p.message=="string"?p.message:"stream error");else if(m==="item.completed"){let f=Wn(p);if(!f)continue;let g=typeof f.type=="string"?f.type:"";if(g==="agent_message"&&typeof f.text=="string"&&f.text.trim())s.push(f.text);else if(g==="error"&&typeof f.message=="string")r.push(f.message);else{let w=or(f);w&&n.push(w)}}}!c&&a.trim()&&Hs("Codex exec output contained no parseable JSONL event",a.trim());let d=s.join(`
|
|
11786
11787
|
|
|
11787
|
-
`).trim();
|
|
11788
|
-
`).trim()),
|
|
11789
|
-
\u25B8 ${n.tool}${
|
|
11790
|
-
`}return null}if(
|
|
11788
|
+
`).trim();d||(d=r.join(`
|
|
11789
|
+
`).trim()),d||(d=e.trim()||"(no output)");let u=s[s.length-1];return{outputText:d,finalResult:u?.trim()?u:void 0,tokensUsed:i>0?i:void 0,costUsd:void 0,toolsUsed:n,concreteModel:void 0,rawJson:l,sessionId:o}},extractStreamChunk(a){let e=to(a);if(!e)return null;let t=typeof e.type=="string"?e.type:"";if(t==="item.completed"){let s=Wn(e);return s&&s.type==="agent_message"&&typeof s.text=="string"&&s.text.trim()?s.text:null}if(t==="item.started"){let s=Wn(e);if(!s)return null;let n=or(s);if(n){let r=n.command?`: ${n.command.slice(0,200)}`:"";return`
|
|
11790
|
+
\u25B8 ${n.tool}${r}
|
|
11791
|
+
`}return null}if(t==="turn.failed"){let s=e.error;return`
|
|
11791
11792
|
\u2716 ${s&&typeof s.message=="string"?s.message:"turn failed"}
|
|
11792
|
-
`}return null},setupPermissions(
|
|
11793
|
-
`)}
|
|
11793
|
+
`}return null},setupPermissions(a,e,t,s){return eo(e,t)}};function Bt(a){let e=(a??"").trim().toLowerCase();return e==="codex"||e==="openai-codex"?"codex":"claude-code"}function ao(a){return Bt(a)==="codex"?zs:Yi}var ro=new Set(["","default","subscription"]);function ts(a,e,t){let s=cr(a?.model);if(s)return{value:dr(s),source:"task"};let n=cr(e.model);if(n)return{value:dr(n),source:"agent"};let r=cr(t.defaultModel);return r?{value:dr(r),source:"settings"}:{value:"",source:"cli-default"}}function Gs(a){return!ro.has(a.trim())}function cr(a){if(!a)return"";let e=a.trim();return e||""}function dr(a){return ro.has(a)?"":a}function io(a,e){let t=a.wikiReferences;if(!t||t.length===0)return null;let s=[];for(let r of t){let i=e.getAgentByName(r.agent);if(!i||!i.wikiKeeper)continue;let o=i.wikiKeeper,l=o.scopeRoot?`${o.scopeRoot.replace(/\/+$/,"")}/`:"";s.push({agentName:i.name,scopeRoot:o.scopeRoot||"(whole vault)",topicsPath:`${l}${o.topicsRoot}`,inboxPath:`${l}${o.inboxPath}`,indexPath:`${l}${o.indexPath}`})}if(s.length===0)return null;let n=["## Wiki Access"];n.push("You have read access to the following wikis maintained by other agents. Use the `wiki-query` skill in consumer mode when the user asks something a wiki may already cover."),n.push("");for(let r of s)n.push(`### Wiki: \`${r.agentName}\``),n.push(`- scope root: \`${r.scopeRoot}\``),n.push(`- topics: \`${r.topicsPath}/\``),n.push(`- index: \`${r.indexPath}\``),n.push(`- inbox: \`${r.inboxPath}/\``),n.push("");return n.push("### Rules"),n.push("- **Cite every factual claim** from a wiki using `[[<topics-path>/<page>]]`. If a claim has no page, say the wiki doesn't cover it \u2014 do not fabricate."),n.push("- **When the user shares something durable** that isn't yet in a wiki (a decision, a new entity mention, a competitor change, a meeting outcome), write a short markdown file to the relevant wiki's inbox at `<inbox>/YYYY-MM-DD-<slug>.md` with a one-line note + the source. The wiki keeper files it canonically on its next ingest."),n.push("- **Do NOT write to `<topics-path>/` directly.** The wiki keeper is the canonical curator of topic pages. Use the inbox as your deposit point."),n.push("- **When the question spans multiple wikis**, be explicit about which scope each cited page belongs to."),n.join(`
|
|
11794
|
+
`)}async function qn(a,e,t){let s=[e.body.trim()];for(let r of e.skills){let i=a.getSkillByName(r);if(i){let o=[i.body.trim()];i.toolsBody.trim()&&o.push(`### Tools
|
|
11795
|
+
${i.toolsBody.trim()}`),i.referencesBody.trim()&&o.push(`### References
|
|
11796
|
+
${i.referencesBody.trim()}`),i.examplesBody.trim()&&o.push(`### Examples
|
|
11797
|
+
${i.examplesBody.trim()}`),s.push(`## Skill: ${i.name}
|
|
11798
|
+
${o.join(`
|
|
11799
|
+
|
|
11800
|
+
`)}`)}}if(e.skillsBody.trim()&&s.push(`## Agent Skills
|
|
11801
|
+
${e.skillsBody.trim()}`),e.contextBody.trim()&&s.push(`## Agent Context
|
|
11802
|
+
${e.contextBody.trim()}`),t.memoryActive){let r=await a.readWorkingMemory(e.name),i=ki(e,r);i&&s.push(i)}t.channelContext&&t.channelContext.trim()&&s.push(`## Channel Context
|
|
11803
|
+
${t.channelContext.trim()}`);let n=io(e,a);return n&&s.push(n),s}var uo=require("crypto"),kt=require("fs"),Gn=require("path");var Fd=require("crypto"),zn=require("fs"),Ld=require("path");var ur="remember",tf=`mcp__${ur}`,oo=String.raw`
|
|
11794
11804
|
const fs = require("fs");
|
|
11795
11805
|
const path = require("path");
|
|
11796
11806
|
const PENDING_DIR = process.env.AF_PENDING_DIR;
|
|
@@ -11882,57 +11892,43 @@ function handle(req) {
|
|
|
11882
11892
|
send({ jsonrpc: "2.0", id, error: { code: -32601, message: "method not found: " + method } });
|
|
11883
11893
|
}
|
|
11884
11894
|
}
|
|
11885
|
-
`;function
|
|
11886
|
-
${
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
${l.join(`
|
|
11890
|
-
|
|
11891
|
-
`)}`)}}if(t.skillsBody.trim()&&a.push(`## Agent Skills
|
|
11892
|
-
${t.skillsBody.trim()}`),t.contextBody.trim()&&a.push(`## Agent Context
|
|
11893
|
-
${t.contextBody.trim()}`),n){let o=await this.repository.readWorkingMemory(t.name),c=Gs(t,o);c&&a.push(c)}let i=rn(t,this.repository);return i&&a.push(i),a.push(`## Task
|
|
11894
|
-
${(s??e.body).trim()}`),a.filter(Boolean).join(`
|
|
11895
|
-
|
|
11896
|
-
`)}async execute(t,e,s,n,a){let i=t.memory&&!a?.suppressMemoryCapture,o=await this.buildPrompt(t,e,s,i),c=(0,hi.randomUUID)(),l=It(e,t,this.settings),h=n!=null,d=ii(t.adapter),u=await d.buildExec({prompt:o,model:ws(l.value)?l.value:"",modelSource:l.source,effort:e.effort||t.effort||"",agent:t,settings:this.settings,streaming:h}),p=t.cwd?.trim()?t.cwd:this.repository.getVaultBasePath()??".",m=i?this.repository.getPendingDirAbsolutePath(t.name):null,f=cn({registry:this.repository.getMcpServers(),agentGrants:t.mcpServers??[],getBearerToken:k=>this.mcpAuth?.getToken(k),remember:m?{pendingDir:m,source:"mcp"}:null}),g=dn(p,t.adapter,f);g&&u.args.push(...g.args);let y=await d.setupPermissions(p,t,this.settings,{mcpAllowServers:f.map(k=>k.def.name)}),v=Date.now();try{return await new Promise((k,w)=>{let S=dt(u.cliPath,u.args,{cwd:p,env:{...process.env,AWS_REGION:this.settings.awsRegion,...g?.env??{},...y?.env??{}}});if(u.stdinPayload!==void 0)try{S.stdin?.write(u.stdinPayload),S.stdin?.end()}catch(C){S.kill(),w(C instanceof Error?C:new Error(String(C)));return}this.runningProcesses.set(t.name,S);let T="",_="",D=!1,O=window.setTimeout(()=>{D=!0,S.kill()},t.timeout*1e3);S.stdout.on("data",C=>{let E=C.toString();if(T+=E,h&&n)for(let P of ye(E)){let N=d.extractStreamChunk(P);N&&n(N)}}),S.stderr.on("data",C=>{_+=C.toString()}),S.on("error",C=>{window.clearTimeout(O),w(C)}),S.on("close",C=>{window.clearTimeout(O),this.runningProcesses.delete(t.name);let E=d.parseExecOutput(T,_,h);k({runId:c,prompt:o,exitCode:C,durationSeconds:Math.max(1,Math.round((Date.now()-v)/1e3)),stdout:T,stderr:_,outputText:E.outputText,rawJson:E.rawJson,tokensUsed:E.tokensUsed,costUsd:E.costUsd,toolsUsed:E.toolsUsed,timedOut:D,resolvedModel:l.value,modelSource:l.source,concreteModel:E.concreteModel,finalResult:E.finalResult})})})}finally{y?.restore(),xt(g)}}};function ui(r){return oe(r).slice(0,60)||"candidate"}function mi(r){let t=Math.max(400,r.tokenBudget*4);return[`You are running a nightly memory **reflection** for the agent "${r.agentName}".`,"Review the raw memory log and your current working memory below, then produce an","updated, consolidated working memory.","","Rules:","- Remove duplicates; resolve contradictions in favor of the NEWEST fact.","- File each fact under exactly one of: Preferences, Procedures, Observations.","- Keep durable user/process preferences, marking them `[pin]` \u2014 never drop or"," summarize pinned Preferences.","- Summarize the Observations section FROM THE RAW LOG (not from prior summaries)",` if needed so the whole memory fits within roughly ${r.tokenBudget} tokens`,` (~${t} characters).`,"- Note any friction that recurred across multiple runs as a skill candidate.","","Reply with EXACTLY these two fenced blocks and nothing else:","","```memory","## Preferences","- [pin] <durable preference> <!-- src:reflection -->","## Procedures","- <how-to learning>","## Observations","- <current fact>","```","","```candidates",'[{"key":"short-stable-key","pattern":"what recurred","evidence":["runs/..."],"suggestedSkill":"optional-name"}]',"```","","If there is nothing worth remembering, still emit a `memory` block preserving the","existing pinned Preferences. Use an empty array `[]` for candidates when none.","","\u2500\u2500 CURRENT WORKING MEMORY \u2500\u2500",r.workingMemoryBody.trim()||"(empty)","","\u2500\u2500 RAW MEMORY LOG (ground truth) \u2500\u2500",r.recentRaw.trim()||"(empty)",r.recentRunsSummary?`
|
|
11895
|
+
`;function lo(a){let e=[];for(let t of a){let s=t.trim();if(s)try{let n=JSON.parse(s),r=typeof n.text=="string"?n.text.trim():"";if(!r)continue;let i=n.section==="Preferences"||n.section==="Procedures"||n.section==="Observations"?n.section:void 0;e.push({text:r,pinned:n.pinned===!0,section:i,source:typeof n.source=="string"?n.source:"mcp"})}catch{}}return e}function Od(a,e){return{def:{name:ur,type:"stdio",enabled:!0,command:"node",env:{AF_PENDING_DIR:a,AF_SOURCE:e},status:"connected",scope:"user",tools:[],toolDetails:[]},inlineScript:oo}}function Vn(a){let e=a.agentGrants.map(n=>n.trim().toLowerCase()).filter(Boolean),t=e.length>0?new Set(e):null,s=[];for(let n of a.registry){if(!n.enabled||t&&!t.has(n.name.trim().toLowerCase())||n.type==="unknown")continue;let r={};if(n.type==="stdio"){if(n.envSecretKeys&&n.envSecretKeys.length>0){let i={};for(let o of n.envSecretKeys){let l=process.env[o];l&&(i[o]=l)}Object.keys(i).length>0&&(r.env=i)}}else if(n.auth!=="none"){let i=a.getBearerToken(n.name);i&&(r.bearerToken=i)}s.push({def:n,secrets:r})}return a.remember&&s.push(Od(a.remember.pendingDir,a.remember.source)),s}function Nd(a){return`AF_MCP_${a.toUpperCase().replace(/[^A-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"SERVER"}_TOKEN`}function co(a){return/^[A-Za-z0-9_-]+$/.test(a)?a:`"${a.replace(/"/g,'\\"')}"`}function Bd(a,e){let{def:t,secrets:s}=a;if(t.type==="unknown")throw new Error(`server ${t.name} has unknown transport`);let n=t.type;if(n==="stdio"){let r=t.command??"node",i=e?[e]:t.args??[],o={...t.env??{},...s?.env??{}};return{name:t.name,type:n,command:r,args:i,env:o}}if(!t.url)throw new Error(`server ${t.name} (${n}) has no url`);return{name:t.name,type:n,url:t.url,headers:t.headers,bearerToken:s?.bearerToken,oauthResource:t.oauth?.resource,oauthClientId:t.oauth?.clientId}}function Ud(a){if(a.type==="stdio"){let s={command:a.command,args:a.args??[]};return a.env&&Object.keys(a.env).length>0&&(s.env=a.env),s}let e={...a.headers??{}};a.bearerToken&&(e.Authorization=`Bearer ${a.bearerToken}`);let t={type:a.type,url:a.url};return Object.keys(e).length>0&&(t.headers=e),t}function $d(a){let e=co(a.name),t=[],s={};if(a.type==="stdio"){t.push("-c",`mcp_servers.${e}.command=${JSON.stringify(a.command??"node")}`),a.args&&a.args.length>0&&t.push("-c",`mcp_servers.${e}.args=${JSON.stringify(a.args)}`);for(let[n,r]of Object.entries(a.env??{}))t.push("-c",`mcp_servers.${e}.env.${co(n)}=${JSON.stringify(r)}`)}else{if(t.push("-c",`mcp_servers.${e}.url=${JSON.stringify(a.url)}`),a.bearerToken){let n=Nd(a.name);s[n]=a.bearerToken,t.push("-c",`mcp_servers.${e}.bearer_token_env_var=${JSON.stringify(n)}`)}a.oauthResource&&t.push("-c",`mcp_servers.${e}.oauth_resource=${JSON.stringify(a.oauthResource)}`),a.oauthClientId&&t.push("-c",`mcp_servers.${e}.oauth.client_id=${JSON.stringify(a.oauthClientId)}`)}return t.push("-c",`mcp_servers.${e}.enabled=true`),{args:t,env:s}}function Yn(a,e,t){if(t.length===0)return null;let s=Bt(e)==="codex",n=[],r=(0,Gn.join)(a,".claude");try{(0,kt.existsSync)(r)||(0,kt.mkdirSync)(r,{recursive:!0});let i=(0,uo.randomUUID)(),o=[],l=0;for(let u of t){try{let h=null;u.inlineScript&&(h=(0,Gn.join)(r,`af-mcp-${jd(u.def.name)}.${i}-${l}.cjs`),(0,kt.writeFileSync)(h,u.inlineScript,"utf-8"),n.push(h)),o.push(Bd(u,h))}catch(h){console.warn(`Agent Fleet: skipping MCP server "${u.def.name}" in projection:`,h)}l++}if(o.length===0)return hr(n),null;if(s){let u=[],h={};for(let p of o){let m=$d(p);u.push(...m.args),Object.assign(h,m.env)}return{args:u,env:h,tempFiles:n}}let c={};for(let u of o)c[u.name]=Ud(u);let d=(0,Gn.join)(r,`af-mcp.${i}.json`);return(0,kt.writeFileSync)(d,JSON.stringify({mcpServers:c},null,2),"utf-8"),n.push(d),{args:["--mcp-config",d],env:{},tempFiles:n}}catch(i){return console.warn("Agent Fleet: couldn't install MCP projection; run proceeds without fleet MCP.",i),hr(n),null}}function Ut(a){a&&hr(a.tempFiles)}function hr(a){for(let e of a)try{(0,kt.existsSync)(e)&&(0,kt.unlinkSync)(e)}catch{}}function jd(a){return a.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"server"}var ho=10*1024*1024,po=1024*1024;var Kn=class{constructor(e,t,s){this.settings=e;this.repository=t;this.mcpAuth=s}runningProcesses=new Map;abortAgent(e){let t=this.runningProcesses.get(e);return t?(t.kill(),this.runningProcesses.delete(e),!0):!1}async buildPrompt(e,t,s,n=e.memory){let r=await qn(this.repository,e,{memoryActive:n});return r.push(`## Task
|
|
11896
|
+
${(s??t.body).trim()}`),r.filter(Boolean).join(`
|
|
11897
|
+
|
|
11898
|
+
`)}async execute(e,t,s,n,r){let i=e.memory&&!r?.suppressMemoryCapture,o=await this.buildPrompt(e,t,s,i),l=(0,mo.randomUUID)(),c=ts(t,e,this.settings),d=n!=null,u=ao(e.adapter),h=await u.buildExec({prompt:o,model:Gs(c.value)?c.value:"",modelSource:c.source,effort:t.effort||e.effort||"",agent:e,settings:this.settings,streaming:d}),p=e.cwd?.trim()?e.cwd:this.repository.getVaultBasePath()??".",m=i?this.repository.getPendingDirAbsolutePath(e.name):null,f=Vn({registry:this.repository.getMcpServers(),agentGrants:e.mcpServers??[],getBearerToken:v=>this.mcpAuth?.getToken(v),remember:m?{pendingDir:m,source:"mcp"}:null}),g=Yn(p,e.adapter,f);g&&h.args.push(...g.args);let w=await u.setupPermissions(p,e,this.settings,{mcpAllowServers:f.map(v=>v.def.name)}),y=Date.now();try{return await new Promise((v,k)=>{let b=wt(h.cliPath,h.args,{cwd:p,env:{...process.env,AWS_REGION:this.settings.awsRegion,...g?.env??{},...w?.env??{}}});if(h.stdinPayload!==void 0)try{b.stdin?.write(h.stdinPayload),b.stdin?.end()}catch(_){b.kill(),k(_ instanceof Error?_:new Error(String(_)));return}this.runningProcesses.set(e.name,b);let P="",A="",M=!1,E=null,x=window.setTimeout(()=>{M=!0,b.kill()},e.timeout*1e3);b.stdout.on("data",_=>{if(E)return;let R=_.toString();if(P+=R,P.length>ho){E=`Run output exceeded the ${ho/(1024*1024)}MB stdout limit \u2014 process killed.`,b.kill();return}if(d&&n)for(let O of re(R)){let F=u.extractStreamChunk(O);F&&n(F)}}),b.stderr.on("data",_=>{E||(A+=_.toString(),A.length>po&&(E=`Run stderr exceeded the ${po/(1024*1024)}MB limit \u2014 process killed.`,b.kill()))}),b.on("error",_=>{window.clearTimeout(x),k(_)}),b.on("close",_=>{if(window.clearTimeout(x),this.runningProcesses.delete(e.name),E){k(new Error(E));return}let R=u.parseExecOutput(P,A,d);v({runId:l,prompt:o,exitCode:_,durationSeconds:Math.max(1,Math.round((Date.now()-y)/1e3)),stdout:P,stderr:A,outputText:R.outputText,rawJson:R.rawJson,tokensUsed:R.tokensUsed,costUsd:R.costUsd,toolsUsed:R.toolsUsed,timedOut:M,resolvedModel:c.value,modelSource:c.source,concreteModel:R.concreteModel,finalResult:R.finalResult})})})}finally{w?.restore(),Ut(g)}}};function fo(a){return z(a).slice(0,60)||"candidate"}function yo(a){let e=Math.max(400,a.tokenBudget*4);return[`You are running a nightly memory **reflection** for the agent "${a.agentName}".`,"Review the raw memory log and your current working memory below, then produce an","updated, consolidated working memory.","","Rules:","- Remove duplicates; resolve contradictions in favor of the NEWEST fact.","- File each fact under exactly one of: Preferences, Procedures, Observations.","- Keep durable user/process preferences, marking them `[pin]` \u2014 never drop or"," summarize pinned Preferences.","- Summarize the Observations section FROM THE RAW LOG (not from prior summaries)",` if needed so the whole memory fits within roughly ${a.tokenBudget} tokens`,` (~${e} characters).`,"- Note any friction that recurred across multiple runs as a skill candidate.","","Reply with EXACTLY these two fenced blocks and nothing else:","","```memory","## Preferences","- [pin] <durable preference> <!-- src:reflection -->","## Procedures","- <how-to learning>","## Observations","- <current fact>","```","","```candidates",'[{"key":"short-stable-key","pattern":"what recurred","evidence":["runs/..."],"suggestedSkill":"optional-name"}]',"```","","If there is nothing worth remembering, still emit a `memory` block preserving the","existing pinned Preferences. Use an empty array `[]` for candidates when none.","","\u2500\u2500 CURRENT WORKING MEMORY \u2500\u2500",a.workingMemoryBody.trim()||"(empty)","","\u2500\u2500 RAW MEMORY LOG (ground truth) \u2500\u2500",a.recentRaw.trim()||"(empty)",a.recentRunsSummary?`
|
|
11897
11899
|
\u2500\u2500 RECENT ACTIVITY \u2500\u2500
|
|
11898
|
-
${
|
|
11899
|
-
`)}function pi(r,t){let e=new RegExp("```"+t+"(?![A-Za-z0-9-])[^\\n]*\\n([\\s\\S]*?)```","i"),s=r.match(e);return s?s[1]??"":null}function fi(r){let t=pi(r,"memory"),e=t!==null?zs(t):null,s=[],n=pi(r,"candidates");if(n!==null&&n.trim())try{let a=JSON.parse(n.trim());Array.isArray(a)&&(s=a.map(i=>cc(i)).filter(i=>i!==null))}catch{}return{sections:e,candidates:s}}function cc(r){if(typeof r!="object"||r===null)return null;let t=r,e=typeof t.pattern=="string"?t.pattern.trim():"";return e?{key:typeof t.key=="string"&&t.key.trim()?ui(t.key):ui(e),pattern:e,evidence:Array.isArray(t.evidence)?t.evidence.filter(n=>typeof n=="string"):[],suggestedSkill:typeof t.suggestedSkill=="string"?t.suggestedSkill:void 0}:null}function gi(r,t,e){let s=new Map;for(let a of r)s.set(a.key,{...a,evidence:[...a.evidence]});let n=new Map;for(let a of t){let i=n.get(a.key);i?(i.evidence=Array.from(new Set([...i.evidence??[],...a.evidence??[]])),a.suggestedSkill&&(i.suggestedSkill=a.suggestedSkill)):n.set(a.key,{...a,evidence:[...a.evidence??[]]})}for(let a of n.values()){let i=s.get(a.key);i?(i.occurrences+=1,i.lastSeen=e,i.evidence=Array.from(new Set([...i.evidence,...a.evidence??[]])),a.suggestedSkill&&(i.suggestedSkill=a.suggestedSkill)):s.set(a.key,{key:a.key,pattern:a.pattern,occurrences:1,firstSeen:e,lastSeen:e,evidence:[...a.evidence??[]],proposed:!1,suggestedSkill:a.suggestedSkill})}return[...s.values()]}var dc=1.5,Gt=class r{constructor(t){this.store=t}static locks=new Map;static __resetLocksForTest(){r.locks.clear()}async capture(t,e,s,n){!t.memory||e.length===0||await this.withLock(t.name,()=>this.applyCaptures(t,e,s,n))}async drainPending(t,e){t.memory&&await this.withLock(t.name,async()=>{let s=await this.store.readAndClearPending(t.name),n=ci(s);if(n.length===0)return;let a=[];for(let i of n){let o=a[a.length-1],c={text:i.text,pinned:i.pinned,section:i.section};o&&o.source===i.source?o.entries.push(c):a.push({source:i.source,entries:[c]})}for(let i of a)await this.applyCaptures(t,i.entries,i.source,e)})}async reflect(t,e,s){return!t.memory||e===null||!e.some(n=>n.entries.length>0)?!1:(await this.withLock(t.name,async()=>{let n=this.store.getWorkingMemoryPath(t.name),a=await this.store.readWorkingMemory(t.name),i=br(a,e),o={filePath:a?.filePath??n,agent:t.name,schema:a?.schema??2,lastUpdated:s,lastReflection:s,tokenEstimate:0,sections:i};await this.store.writeWorkingMemory(t.name,o)}),!0)}async applyCaptures(t,e,s,n){let a=e.map(p=>({...p,text:pr(p.text)})).filter(p=>p.text);if(a.length===0)return;await this.store.migrateLegacyMemory?.(t.name);let i=this.store.getWorkingMemoryPath(t.name),o=await this.store.readWorkingMemory(t.name)??mr(i,t.name),c=n.slice(0,10),l=a.map(p=>`- ${n} [${s}]${p.pinned?" [pin]":""} ${p.text}`);await this.store.appendRawMemory(t.name,l,n);let h=new Set(o.sections.flatMap(p=>p.entries).map(p=>p.text.trim().toLowerCase())),d=o;for(let p of a){let m=p.text.trim().toLowerCase();if(h.has(m))continue;h.add(m);let f={text:p.text,source:s,date:c,pinned:p.pinned??!1},g=p.section??(p.pinned?"Preferences":hr);d=vr(d,[f],g,n)}let u=Math.ceil((t.memoryTokenBudget||0)*dc);if(u>0){let{wm:p,spilled:m}=wr(d,u);m.length>0&&console.info(`Agent Fleet: working memory for "${t.name}" exceeded hard cap; spilled ${m.length} entr${m.length===1?"y":"ies"} to raw-only (still in the archive). A reflection pass will consolidate.`),d=p}await this.store.writeWorkingMemory(t.name,d)}withLock(t,e){let n=(r.locks.get(t)??Promise.resolve()).then(e,e);return r.locks.set(t,n.then(()=>{},()=>{})),n}};var bs=Ye(require("crypto")),yi=Ye(require("https")),un=Ye(require("http")),vi=Ye(require("fs")),xa=Ye(require("path"));var pn=class{constructor(t){this.settings=t;this.settings}authManager;setAuthManager(t){this.authManager=t}async probeServer(t){try{if(t.type==="stdio"&&t.command)return(await this.probeStdioServer(t.command,t.args)).tools;if((t.type==="http"||t.type==="sse")&&t.url)return await this.probeHttpServer(t)}catch(e){console.warn(`McpManager: probe failed for ${t.name}:`,e)}return[]}async authenticateServer(t,e,s="http"){let n=await this.discoverOAuthMetadata(e);if(!n)throw new Error("Server does not support OAuth \u2014 no authorization metadata found.");let{metadata:a,resourceScopes:i,resource:o}=n;if(!a.registration_endpoint)throw new Error("Server does not support Dynamic Client Registration.");let c=await this.startOAuthCallbackServer(),l=`http://localhost:${c.port}/callback`;try{let h=await this.registerOAuthClient(a.registration_endpoint,l),d=bs.randomBytes(32).toString("base64url"),u=bs.createHash("sha256").update(d).digest("base64url"),p=bs.randomBytes(16).toString("hex"),m=new URLSearchParams({response_type:"code",client_id:h,code_challenge:u,code_challenge_method:"S256",redirect_uri:l,state:p,resource:o}),f=i??a.scopes_supported;f?.length&&m.set("scope",f.join(" "));let g=new URL(a.authorization_endpoint);for(let[w,S]of m)g.searchParams.set(w,S);let y=g.toString();Cr(y);let v=await c.waitForCode(p,18e4),k=await this.exchangeOAuthCode(a.token_endpoint,v,l,h,d);this.authManager?.storeOAuthToken(t,{accessToken:k.access_token,refreshToken:k.refresh_token,expiresAt:k.expires_in?Date.now()+k.expires_in*1e3:void 0,tokenEndpoint:a.token_endpoint,clientId:h,resource:o})}finally{c.close()}}async refreshProbeTokens(){if(!this.authManager)return;let t=this.authManager.getExpiringTokens();for(let[e,s]of t)if(s.refreshToken)try{let n=new URLSearchParams({grant_type:"refresh_token",refresh_token:s.refreshToken,client_id:s.clientId}).toString(),a=await this.oauthFetch(s.tokenEndpoint,"POST",n,"application/x-www-form-urlencoded");if(a.status===200){let i=JSON.parse(a.body),o=i.access_token;o&&this.authManager.storeOAuthToken(e,{accessToken:o,refreshToken:i.refresh_token??s.refreshToken,expiresAt:typeof i.expires_in=="number"?Date.now()+i.expires_in*1e3:void 0,tokenEndpoint:s.tokenEndpoint,clientId:s.clientId,resource:s.resource})}}catch(n){console.warn(`McpManager: failed to refresh token for ${e}:`,n)}}async discoverOAuthMetadata(t){let e=t.endsWith("/sse")?t.replace(/\/sse$/,"/mcp"):t,s=new URL(e),n;try{let d=await this.oauthFetch(e,"POST","{}","application/json");d.status===401&&(n=d.headers?.["www-authenticate"]?.match(/resource_metadata="([^"]+)"/)?.[1])}catch{}n||(n=`${s.origin}/.well-known/oauth-protected-resource${s.pathname}`);let a=s.origin,i,o=e;try{let d=await this.oauthFetch(n,"GET");if(d.status===200){let u=JSON.parse(d.body),p=u.authorization_servers;p?.[0]&&(a=p[0]),Array.isArray(u.scopes_supported)&&(i=u.scopes_supported),typeof u.resource=="string"&&(o=u.resource)}}catch{}let c=new URL(a),l=c.pathname==="/"?"":c.pathname,h=`${c.origin}/.well-known/oauth-authorization-server${l}`;try{let d=await this.oauthFetch(h,"GET");if(d.status===200)return{metadata:JSON.parse(d.body),resourceScopes:i,resource:o}}catch{}if(l){let d=`${c.origin}/.well-known/oauth-authorization-server`;try{let u=await this.oauthFetch(d,"GET");if(u.status===200)return{metadata:JSON.parse(u.body),resourceScopes:i,resource:o}}catch{}}return null}async registerOAuthClient(t,e){let s=JSON.stringify({client_name:"Agent Fleet Obsidian Plugin",redirect_uris:[e],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"}),n=await this.oauthFetch(t,"POST",s,"application/json");if(n.status!==200&&n.status!==201)throw new Error(`Client registration failed (HTTP ${n.status})`);let a=JSON.parse(n.body);if(!a.client_id)throw new Error("Client registration response missing client_id");return a.client_id}async startOAuthCallbackServer(){let t=null,e=null,s=un.createServer((a,i)=>{let o=new URL(a.url??"/","http://localhost");if(o.pathname!=="/callback"){i.writeHead(404),i.end();return}let c=o.searchParams.get("error");if(c){let d=o.searchParams.get("error_description")??c;i.writeHead(200,{"Content-Type":"text/html"}),i.end("<html><body style='font-family:system-ui;text-align:center;padding:60px'><h2>Authorization Failed</h2><p>"+d+"</p><p style='color:#888'>You can close this tab.</p></body></html>"),e?.(new Error(`OAuth denied: ${d}`));return}let l=o.searchParams.get("code"),h=o.searchParams.get("state");if(!l||!h){i.writeHead(400),i.end("Missing code or state");return}i.writeHead(200,{"Content-Type":"text/html"}),i.end("<html><body style='font-family:system-ui;text-align:center;padding:60px'><h2 style='color:#22c55e'>Authenticated!</h2><p>You can close this tab and return to Obsidian.</p><script>window.setTimeout(()=>window.close(),2000)</script></body></html>"),t?.(l,h)});return{port:await new Promise((a,i)=>{s.listen(0,"127.0.0.1",()=>{let o=s.address();if(!o||typeof o=="string"){i(new Error("Failed to bind callback server"));return}a(o.port)}),s.on("error",i)}),waitForCode:(a,i)=>new Promise((o,c)=>{let l=window.setTimeout(()=>{c(new Error("Authentication timed out \u2014 complete authorization in your browser and try again."))},i);t=(h,d)=>{window.clearTimeout(l),d!==a?c(new Error("OAuth state mismatch \u2014 possible CSRF attack")):o(h)},e=h=>{window.clearTimeout(l),c(h)}}),close:()=>{try{s.close()}catch{}}}}async exchangeOAuthCode(t,e,s,n,a){let i=new URLSearchParams({grant_type:"authorization_code",code:e,redirect_uri:s,client_id:n,code_verifier:a}).toString(),o=await this.oauthFetch(t,"POST",i,"application/x-www-form-urlencoded");if(o.status!==200)throw new Error(`Token exchange failed (HTTP ${o.status}): ${o.body}`);let c=JSON.parse(o.body);if(!c.access_token)throw new Error("Token response missing access_token");return c}oauthFetch(t,e,s,n){return new Promise((a,i)=>{let o=new URL(t),c=o.protocol==="https:",l={Accept:"application/json"};s&&(l["Content-Type"]=n??"application/json",l["Content-Length"]=String(Buffer.byteLength(s)));let h={hostname:o.hostname,port:o.port||(c?443:80),path:o.pathname+o.search,method:e,headers:l},u=(c?yi:un).request(h,m=>{let f="";m.on("data",g=>{f+=g.toString()}),m.on("end",()=>{let g={};for(let[y,v]of Object.entries(m.headers))typeof v=="string"?g[y]=v:Array.isArray(v)&&(g[y]=v.join(", "));a({status:m.statusCode??0,body:f,headers:g})})});u.on("error",i);let p=window.setTimeout(()=>{u.destroy(),i(new Error("OAuth request timed out"))},15e3);u.on("close",()=>window.clearTimeout(p)),s&&u.write(s),u.end()})}probeStdioServer(t,e){return new Promise(s=>{let n=e&&e.length>0?`${t} ${e.join(" ")}`:t,a=Sr(n,{env:{...process.env}}),i="",o,c=[],l=!1,h=!1,d=!1,u=()=>{l||(l=!0,a.kill(),s({description:o,tools:c}))},p=window.setTimeout(u,1e4);a.stdout.on("data",m=>{i+=m.toString();let f=ye(i);i=f.pop()??"";for(let g of f){let y=g.trim();if(y){try{let v=JSON.parse(y);if(v.id===1&&v.result){o=v.result.instructions??v.result.serverInfo?.description,h=!0;try{a.stdin.write(JSON.stringify({jsonrpc:"2.0",method:"notifications/initialized"})+`
|
|
11900
|
-
`),
|
|
11901
|
-
`)}catch{window.clearTimeout(p),
|
|
11902
|
-
`)}catch{window.clearTimeout(p),u()}})}async probeHttpServer(t){let e=await this.findServerToken(t);if(!e)return[];let s=t.url.endsWith("/sse")?t.url.replace(/\/sse$/,"/mcp"):t.url;try{let a=(await this.httpRequest(s,e,{jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-03-26",capabilities:{},clientInfo:{name:"agent-fleet",version:"1.0.0"}}}))?._sessionId;await this.httpRequest(s,e,{jsonrpc:"2.0",method:"notifications/initialized"},a);let i=await this.httpRequest(s,e,{jsonrpc:"2.0",id:2,method:"tools/list"},a),o=[],h=i?.result?.tools??[];for(let d of h)o.push({name:d.name,description:d.description,inputSchema:d.inputSchema});return o}catch(n){return console.warn(`McpManager: HTTP probe failed for ${t.name}:`,n),[]}}async findServerToken(t){if(this.authManager){let a=this.authManager.getToken(t.name);if(a)return a}let e=t.name.replace(/^claude\.ai\s+/i,"").replace(/\s+/g,"_").toUpperCase(),s=[`${e}_API_KEY`,`${e}_API_KEY_MILO`,`${e}_TOKEN`];for(let a of s){let i=process.env[a];if(i)return i}let n=[xa.join(ea(),".openclaw","workspace",".env"),xa.join(ea(),".env")];for(let a of n)try{let i=vi.readFileSync(a,"utf8");for(let o of ye(i)){let c=o.trim().match(/^(?:export\s+)?([A-Za-z_]\w*)=(.*)$/);if(c){let l=c[1],h=c[2].replace(/^["']|["']$/g,"");if(s.includes(l))return h}}}catch{}}httpRequest(t,e,s,n){return new Promise((a,i)=>{let o=JSON.stringify(s),c=new URL(t),l=c.protocol==="https:",h={"Content-Type":"application/json",Accept:"application/json, text/event-stream",Authorization:`Bearer ${e}`,"Content-Length":String(Buffer.byteLength(o))};n&&(h["mcp-session-id"]=n);let d={hostname:c.hostname,port:c.port||(l?443:80),path:c.pathname+c.search,method:"POST",headers:h},p=(l?yi:un).request(d,f=>{let g="";f.on("data",y=>{g+=y.toString()}),f.on("end",()=>{let y=f.headers["mcp-session-id"];if((f.headers["content-type"]??"").includes("text/event-stream")){for(let k of ye(g))if(k.startsWith("data: "))try{let w=JSON.parse(k.slice(6));y&&(w._sessionId=y),a(w);return}catch{}a(null)}else try{let k=JSON.parse(g);y&&(k._sessionId=y),a(k)}catch{a(null)}})});p.on("error",i);let m=window.setTimeout(()=>{p.destroy(),a(null)},15e3);p.on("close",()=>window.clearTimeout(m)),p.write(o),p.end()})}};var hc={"every 5m":"*/5 * * * *","every 10m":"*/10 * * * *","every 15m":"*/15 * * * *","every 30m":"*/30 * * * *","every 1h":"0 * * * *","every 2h":"0 */2 * * *",hourly:"0 * * * *","daily at 9am":"0 9 * * *","daily at 6pm":"0 18 * * *","weekdays at 9am":"0 9 * * 1-5","weekly on monday":"0 9 * * 1","monthly on 1st":"0 9 1 * *"},mn=class{constructor(t,e){this.maxConcurrentRuns=t;this.callbacks=e}jobs=new Map;activeRuns=0;queue=[];paused=!1;setMaxConcurrentRuns(t){this.maxConcurrentRuns=t}parseSchedule(t){return hc[t.toLowerCase()]??t}toLocalISOString(t){let e=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}T${e(t.getHours())}:${e(t.getMinutes())}:${e(t.getSeconds())}`}async registerTask(t){if(this.unregisterTask(t.taskId),!(!t.enabled||t.type==="immediate"))try{if(t.type==="once"&&t.runAt){let e=new pe(new Date(t.runAt),{name:t.taskId,catch:!0},()=>{this.enqueue({task:t,reason:"scheduled"})});this.jobs.set(t.taskId,e),await this.callbacks.onTaskScheduled(t,t.runAt);return}if(t.type==="recurring"&&t.schedule){let e=this.parseSchedule(t.schedule),s=new pe(e,{name:t.taskId,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.enqueue({task:t,reason:"scheduled"})});this.jobs.set(t.taskId,s);let n=s.nextRun();await this.callbacks.onTaskScheduled(t,n?this.toLocalISOString(n):void 0)}}catch(e){console.error(`Agent Fleet: Failed to register task "${t.taskId}":`,e)}}unregisterTask(t){let e=this.jobs.get(t);e&&(e.stop(),this.jobs.delete(t))}async loadTasks(t){for(let e of t)await this.registerTask(e)}async handleStartupCatchUp(t){let e=Date.now();for(let s of t)!s.enabled||!s.catchUp||!s.nextRun||new Date(s.nextRun).getTime()<e&&await this.enqueue({task:s,reason:"catch-up"})}async enqueue(t){this.queue.push(t),await this.processQueue()}pauseAll(){this.paused=!0,this.jobs.forEach(t=>t.pause())}resumeAll(){this.paused=!1,this.jobs.forEach(t=>t.resume()),this.processQueue()}shutdown(){this.paused=!0,this.jobs.forEach(t=>t.stop()),this.jobs.clear(),this.queue.length=0}getQueueSize(){return this.queue.length}async processQueue(){if(!this.paused)for(;this.activeRuns<this.maxConcurrentRuns&&this.queue.length>0;){let t=this.queue.shift();if(!t)return;this.activeRuns+=1,this.callbacks.onTaskTriggered(t).finally(async()=>{this.activeRuns-=1,await this.processQueue()})}}};var ks=class r{constructor(t,e,s){this.repository=t;this.settings=e;this.executor=new hn(e,t,s),this.mcpManager=new pn(e),s&&this.mcpManager.setAuthManager(s),this.memoryWriter=new Gt(t),this.scheduler=new mn(e.maxConcurrentRuns,{onTaskTriggered:n=>this.runPendingTask(n),onTaskScheduled:(n,a)=>this.repository.updateTaskRunMetadata(n,{nextRun:a})})}scheduler;executor;mcpManager;snapshot={agents:[],skills:[],tasks:[],channels:[],mcpServers:[],validationIssues:[]};runtimeState=new Map;recentRuns=[];chartRuns=[];static CHART_WINDOW_DAYS=14;recentUsage=[];statusChangeListeners=new Set;runOutputListeners=new Map;runOutputBuffers=new Map;heartbeatJobs=new Map;reflectionJobs=new Map;reflectionsInFlight=new Set;reflectionRunning=0;reflectionWaiters=[];heartbeatRegisteredAt=0;heartbeatsInFlight=new Set;channelResultHandler;memoryWriter;async initialize(){this.snapshot=await this.repository.loadAll(),await this.repository.migrateAllLegacyMemory(),await this.refreshRunCaches();let t=this.snapshot.tasks.filter(e=>this.repository.getAgentByName(e.agent)?.enabled!==!1);await this.scheduler.loadTasks(t),await this.scheduler.handleStartupCatchUp(t),this.registerHeartbeats(),this.registerReflections(),this.emitStatusChange()}onChannelResult(t){this.channelResultHandler=t}async refreshFromVault(){this.snapshot=await this.repository.loadAll(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}getSnapshot(){return this.snapshot}getRecentRuns(){return this.recentRuns}getChartRuns(){return this.chartRuns}async refreshRunCaches(){this.recentRuns=await this.repository.listRecentRuns();let t=new Date;t.setDate(t.getDate()-(r.CHART_WINDOW_DAYS-1)),this.chartRuns=await this.repository.listRunsSince(t),this.recentUsage=await this.repository.readUsageSince(t)}getUsageRecords(){return this.recentUsage}recordUsage(t){this.recentUsage.push(t),this.repository.appendUsage(t).catch(e=>{console.warn("Agent Fleet: failed to append usage record",e)}),this.emitStatusChange()}getAgentState(t){let e=this.runtimeState.get(t),s=this.snapshot.agents.find(n=>n.name===t);return s&&!s.enabled?{status:"disabled",lastRun:e?.lastRun,currentRunId:e?.currentRunId}:e??{status:"idle"}}getFleetStatus(){let t=new Date,e=o=>String(o).padStart(2,"0"),s=`${t.getFullYear()}-${e(t.getMonth()+1)}-${e(t.getDate())}`,n=this.recentRuns.filter(o=>{let c=new Date(o.started);return`${c.getFullYear()}-${e(c.getMonth()+1)}-${e(c.getDate())}`===s}).length,a=Array.from(this.runtimeState.values()).filter(o=>o.status==="running").length,i=this.recentRuns.flatMap(o=>o.approvals??[]).filter(o=>o.status==="pending").length;return{running:a,pending:i,completedToday:n}}subscribe(t){return this.statusChangeListeners.add(t),()=>this.statusChangeListeners.delete(t)}onRunOutput(t,e){let s=this.runOutputListeners.get(t);s||(s=new Set,this.runOutputListeners.set(t,s)),s.add(e);let n=this.runOutputBuffers.get(t);return n&&e(n),()=>{this.runOutputListeners.get(t)?.delete(e)}}getRunOutputBuffer(t){return this.runOutputBuffers.get(t)??""}async handleVaultChange(t){await this.repository.loadFile(t),this.snapshot=this.repository.getSnapshot(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}async handleVaultDelete(t){this.repository.removeFile(t),this.snapshot=this.repository.getSnapshot(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}abortedAgents=new Set;abortAgentRun(t){let e=this.executor.abortAgent(t);return e&&(this.abortedAgents.add(t),this.runtimeState.set(t,{status:"idle"}),this.emitStatusChange()),e}wasAborted(t){return this.abortedAgents.has(t)}consumeAborted(t){let e=this.abortedAgents.has(t);return this.abortedAgents.delete(t),e}async runTaskNow(t,e){await this.scheduler.enqueue({task:{...t,type:"immediate"},reason:"manual",promptOverride:e})}async runAgentNow(t,e){let s=t.heartbeatBody.trim()&&e==="Run now and summarize the current state."?t.heartbeatBody.trim():e,n=s===t.heartbeatBody.trim()&&t.heartbeatBody.trim().length>0,a={filePath:"",taskId:n?`heartbeat-${Date.now()}`:`manual-${Date.now()}`,agent:t.name,type:"immediate",priority:"medium",enabled:!0,created:new Date().toISOString(),runCount:0,catchUp:!1,tags:n?[...t.tags,"heartbeat"]:t.tags,body:s};await this.scheduler.enqueue({task:a,reason:n?"heartbeat":"manual",promptOverride:s})}async resolveApproval(t,e,s){t.filePath&&(await this.repository.setApprovalDecision(t.filePath,e,s),await this.refreshRunCaches(),this.emitStatusChange())}async pruneOldRuns(){let t=Date.now()-this.settings.runLogRetentionDays*24*60*60*1e3,e=await this.repository.listRecentRuns(500);for(let s of e)s.filePath&&new Date(s.started).getTime()<t&&await this.repository.trashFile(s.filePath)}async rebuildSchedules(){this.scheduler.pauseAll();for(let t of this.snapshot.tasks)this.scheduler.unregisterTask(t.taskId);this.scheduler.setMaxConcurrentRuns(this.settings.maxConcurrentRuns),await this.scheduler.loadTasks(this.snapshot.tasks.filter(t=>this.repository.getAgentByName(t.agent)?.enabled!==!1)),this.scheduler.resumeAll(),this.registerHeartbeats(),this.registerReflections()}shutdown(){for(let[,t]of this.heartbeatJobs)t.stop();this.heartbeatJobs.clear(),this.heartbeatsInFlight.clear();for(let[,t]of this.reflectionJobs)t.stop();this.reflectionJobs.clear(),this.reflectionsInFlight.clear(),this.scheduler.shutdown()}registerHeartbeats(){for(let[,t]of this.heartbeatJobs)t.stop();this.heartbeatJobs.clear(),this.heartbeatRegisteredAt=Date.now();for(let t of this.snapshot.agents)if(!(!t.enabled||!t.heartbeatEnabled||!t.heartbeatSchedule.trim()||!t.heartbeatBody.trim()))try{let e=new pe(t.heartbeatSchedule,{name:`heartbeat:${t.name}`,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.runHeartbeat(t.name)});this.heartbeatJobs.set(t.name,e)}catch(e){console.error(`Agent Fleet: failed to register heartbeat for "${t.name}":`,e)}}async runHeartbeat(t){if(!(Date.now()-this.heartbeatRegisteredAt<1e4)&&!this.heartbeatsInFlight.has(t)){this.heartbeatsInFlight.add(t);try{let e=this.repository.getAgentByName(t);if(!e||!e.enabled||!e.heartbeatBody.trim())return;let s={filePath:"",taskId:`heartbeat-${Date.now()}`,agent:e.name,type:"immediate",priority:"medium",enabled:!0,created:new Date().toISOString(),runCount:0,catchUp:!1,tags:[...e.tags,"heartbeat"],body:e.heartbeatBody.trim()};await this.scheduler.enqueue({task:s,reason:"heartbeat",promptOverride:e.heartbeatBody.trim()})}finally{this.heartbeatsInFlight.delete(t)}}}getNextHeartbeat(t){let e=this.heartbeatJobs.get(t);return e?e.nextRun()??null:null}registerReflections(){for(let[,t]of this.reflectionJobs)t.stop();this.reflectionJobs.clear();for(let t of this.snapshot.agents){if(!t.enabled||!t.memory||!t.reflection.enabled)continue;let e=t.reflection.schedule.trim();if(e)try{let s=new pe(e,{name:`reflection:${t.name}`,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.runReflection(t.name)});this.reflectionJobs.set(t.name,s)}catch(s){console.error(`Agent Fleet: failed to register reflection for "${t.name}":`,s)}}}getNextReflection(t){return this.reflectionJobs.get(t)?.nextRun()??null}async runReflectionNow(t){return this.runReflection(t)}async listPendingProposals(){return(await this.repository.listProposals()).filter(e=>e.status==="pending")}async acceptProposal(t){let e=await this.repository.readProposal(t);if(!e)return{ok:!1,message:"Proposal not found."};try{let s=await this.repository.applyProposal(e);return s?(await this.repository.setProposalStatus(t,"accepted"),await this.refreshFromVault(),{ok:!0,message:`Applied \u2192 ${s}`}):{ok:!1,message:"Couldn't apply \u2014 target skill not found; proposal left pending."}}catch(s){return{ok:!1,message:`Failed to apply: ${s instanceof Error?s.message:String(s)}`}}}async rejectProposal(t){await this.repository.setProposalStatus(t,"rejected"),this.emitStatusChange()}async withReflectionSlot(t){let e=Math.max(1,this.settings.maxConcurrentRuns);this.reflectionRunning>=e?await new Promise(s=>this.reflectionWaiters.push(s)):this.reflectionRunning++;try{return await t()}finally{let s=this.reflectionWaiters.shift();s?s():this.reflectionRunning--}}async runReflection(t){let e=this.repository.getAgentByName(t);if(!e||!e.enabled||!e.memory)return{ok:!1,message:"Agent not found, disabled, or memory off."};if(this.reflectionsInFlight.has(t))return{ok:!1,message:"A reflection is already in progress."};this.reflectionsInFlight.add(t);let s=new Date().toISOString(),n=s,a=`reflection-${Date.now()}`;this.runtimeState.set(t,{status:"running",currentTaskId:a,runStarted:s}),this.runOutputBuffers.set(t,""),this.emitStatusChange();try{await this.repository.migrateLegacyMemory(t);let i=await this.repository.readWorkingMemory(t),o=i?Ke(i.sections):"",c=await this.repository.readRecentRaw(t,2),l=mi({agentName:t,workingMemoryBody:o,recentRaw:c,tokenBudget:e.memoryTokenBudget}),h={filePath:"",taskId:a,agent:e.name,type:"immediate",priority:"low",enabled:!0,created:n,runCount:0,catchUp:!1,tags:[...e.tags,"reflection"],body:l,model:e.reflection.model||void 0},d=await this.withReflectionSlot(()=>this.executor.execute(e,h,l,v=>{let k=this.runOutputBuffers.get(t)??"";this.runOutputBuffers.set(t,k+v);let w=this.runOutputListeners.get(t);if(w)for(let S of w)S(v)},{suppressMemoryCapture:!0})),u=fi(d.outputText),p=await this.memoryWriter.reflect(e,u.sections,n);if(u.candidates.length>0){let v=await this.repository.readCandidates(t),k=gi(v,u.candidates,n);await this.repository.writeCandidates(t,k),await this.generateProposals(e,k,n)}let m=p?"Reflection complete \u2014 working memory consolidated.":"Reflection produced no memory block; working memory left unchanged.",f=d.exitCode===0||d.exitCode===null?"success":"failure",g={runId:d.runId,agent:e.name,task:a,status:f,started:s,completed:new Date().toISOString(),durationSeconds:d.durationSeconds,tokensUsed:d.tokensUsed,costUsd:d.costUsd,model:d.resolvedModel||e.reflection.model||e.model,modelSource:d.modelSource,concreteModel:d.concreteModel,exitCode:d.exitCode,tags:Array.from(new Set([...e.tags,"reflection"])),prompt:d.prompt,output:d.outputText,toolsUsed:d.toolsUsed.map(v=>`${v.tool}${v.command?`: ${v.command}`:""}`),finalResult:m,stderr:d.stderr},y=await this.repository.writeRunLog(g);return await this.refreshRunCaches(),this.runtimeState.set(t,{status:f==="success"?"idle":"error",currentRunId:d.runId,lastRun:{...g,filePath:y}}),{ok:p,message:m}}catch(i){let o=i instanceof Error?i.message:String(i);console.warn(`Agent Fleet: reflection failed for "${t}":`,i);let c={runId:(0,Sa.randomUUID)(),agent:t,task:a,status:"failure",started:s,completed:new Date().toISOString(),durationSeconds:Math.round((Date.now()-new Date(s).getTime())/1e3),model:e.reflection.model||e.model,exitCode:1,tags:Array.from(new Set([...e.tags,"reflection"])),prompt:"",output:`Reflection failed: ${o}`,toolsUsed:[]},l=c;try{let h=await this.repository.writeRunLog(c);await this.refreshRunCaches(),l={...c,filePath:h}}catch(h){console.warn(`Agent Fleet: failed to write reflection run log for "${t}"`,h)}return this.runtimeState.set(t,{status:"error",lastRun:l}),{ok:!1,message:`Reflection failed: ${o}`}}finally{this.reflectionsInFlight.delete(t),this.runOutputBuffers.delete(t),this.runOutputListeners.delete(t),this.emitStatusChange()}}async generateProposals(t,e,s){if(!t.reflection.proposeSkills)return;let n=t.reflection.recurrenceThreshold||3;for(let a of e){if(a.proposed||a.occurrences<n)continue;let o={id:`prop-${s.slice(0,10)}-${a.key}`.slice(0,80),type:"skill_create",agent:t.name,status:"pending",created:s,targetSkill:a.suggestedSkill||a.key,candidate:a.key,evidence:a.evidence,rationale:a.pattern,body:`This skill was proposed by reflection because the following friction recurred ${a.occurrences} times:
|
|
11900
|
+
${a.recentRunsSummary.trim()}`:""].join(`
|
|
11901
|
+
`)}function go(a,e){let t=new RegExp("```"+e+"(?![A-Za-z0-9-])[^\\n]*\\n([\\s\\S]*?)```","i"),s=a.match(t);return s?s[1]??"":null}function vo(a){let e=go(a,"memory"),t=e!==null?_n(e):null,s=[],n=go(a,"candidates");if(n!==null&&n.trim())try{let r=JSON.parse(n.trim());Array.isArray(r)&&(s=r.map(i=>Hd(i)).filter(i=>i!==null))}catch{}return{sections:t,candidates:s}}function Hd(a){if(typeof a!="object"||a===null)return null;let e=a,t=typeof e.pattern=="string"?e.pattern.trim():"";return t?{key:typeof e.key=="string"&&e.key.trim()?fo(e.key):fo(t),pattern:t,evidence:Array.isArray(e.evidence)?e.evidence.filter(n=>typeof n=="string"):[],suggestedSkill:typeof e.suggestedSkill=="string"?e.suggestedSkill:void 0}:null}function wo(a,e,t){let s=new Map;for(let r of a)s.set(r.key,{...r,evidence:[...r.evidence]});let n=new Map;for(let r of e){let i=n.get(r.key);i?(i.evidence=Array.from(new Set([...i.evidence??[],...r.evidence??[]])),r.suggestedSkill&&(i.suggestedSkill=r.suggestedSkill)):n.set(r.key,{...r,evidence:[...r.evidence??[]]})}for(let r of n.values()){let i=s.get(r.key);i?(i.occurrences+=1,i.lastSeen=t,i.evidence=Array.from(new Set([...i.evidence,...r.evidence??[]])),r.suggestedSkill&&(i.suggestedSkill=r.suggestedSkill)):s.set(r.key,{key:r.key,pattern:r.pattern,occurrences:1,firstSeen:t,lastSeen:t,evidence:[...r.evidence??[]],proposed:!1,suggestedSkill:r.suggestedSkill})}return[...s.values()]}var Wd=1.5,fs=class a{constructor(e){this.store=e}static locks=new Map;static __resetLocksForTest(){a.locks.clear()}async capture(e,t,s,n){!e.memory||t.length===0||await this.withLock(e.name,()=>this.applyCaptures(e,t,s,n))}async drainPending(e,t){e.memory&&await this.withLock(e.name,async()=>{let s=await this.store.readAndClearPending(e.name),n=lo(s);if(n.length===0)return;let r=[];for(let i of n){let o=r[r.length-1],l={text:i.text,pinned:i.pinned,section:i.section};o&&o.source===i.source?o.entries.push(l):r.push({source:i.source,entries:[l]})}for(let i of r)await this.applyCaptures(e,i.entries,i.source,t)})}async reflect(e,t,s){return!e.memory||t===null||!t.some(n=>n.entries.length>0)?!1:(await this.withLock(e.name,async()=>{let n=this.store.getWorkingMemoryPath(e.name),r=await this.store.readWorkingMemory(e.name),i=bi(r,t),o={filePath:r?.filePath??n,agent:e.name,schema:r?.schema??2,lastUpdated:s,lastReflection:s,tokenEstimate:0,sections:i};await this.store.writeWorkingMemory(e.name,o)}),!0)}async applyCaptures(e,t,s,n){let r=t.map(p=>({...p,text:pi(p.text)})).filter(p=>p.text);if(r.length===0)return;await this.store.migrateLegacyMemory?.(e.name);let i=this.store.getWorkingMemoryPath(e.name),o=await this.store.readWorkingMemory(e.name)??mi(i,e.name),l=n.slice(0,10),c=r.map(p=>`- ${n} [${s}]${p.pinned?" [pin]":""} ${p.text}`);await this.store.appendRawMemory(e.name,c,n);let d=new Set(o.sections.flatMap(p=>p.entries).map(p=>p.text.trim().toLowerCase())),u=o;for(let p of r){let m=p.text.trim().toLowerCase();if(d.has(m))continue;d.add(m);let f={text:p.text,source:s,date:l,pinned:p.pinned??!1},g=p.section??(p.pinned?"Preferences":ui);u=vi(u,[f],g,n)}let h=Math.ceil((e.memoryTokenBudget||0)*Wd);if(h>0){let{wm:p,spilled:m}=wi(u,h);m.length>0&&console.info(`Agent Fleet: working memory for "${e.name}" exceeded hard cap; spilled ${m.length} entr${m.length===1?"y":"ies"} to raw-only (still in the archive). A reflection pass will consolidate.`),u=p}await this.store.writeWorkingMemory(e.name,u)}static LOCK_TIMEOUT_MS=1e4;withLock(e,t){let s=a.locks.get(e)??Promise.resolve(),n,r=new Promise(l=>{n=l}),i=()=>{let l=setTimeout(()=>{console.warn(`Agent Fleet: memory write for "${e}" still pending after ${a.LOCK_TIMEOUT_MS}ms \u2014 releasing its lock slot`),n()},a.LOCK_TIMEOUT_MS),c=t();return c.then(()=>{clearTimeout(l),n()},()=>{clearTimeout(l),n()}),c},o=s.then(i,i);return a.locks.set(e,r),o}};var Vs=st(require("crypto")),bo=st(require("https")),Jn=st(require("http")),ko=st(require("fs")),pr=st(require("path"));var Xn=class{constructor(e){this.settings=e;this.settings}authManager;setAuthManager(e){this.authManager=e}async probeServer(e){try{if(e.type==="stdio"&&e.command)return(await this.probeStdioServer(e.command,e.args)).tools;if((e.type==="http"||e.type==="sse")&&e.url)return await this.probeHttpServer(e)}catch(t){console.warn(`McpManager: probe failed for ${e.name}:`,t)}return[]}async authenticateServer(e,t,s="http"){let n=await this.discoverOAuthMetadata(t);if(!n)throw new Error("Server does not support OAuth \u2014 no authorization metadata found.");let{metadata:r,resourceScopes:i,resource:o}=n;if(!r.registration_endpoint)throw new Error("Server does not support Dynamic Client Registration.");let l=await this.startOAuthCallbackServer(),c=`http://localhost:${l.port}/callback`;try{let d=await this.registerOAuthClient(r.registration_endpoint,c),u=Vs.randomBytes(32).toString("base64url"),h=Vs.createHash("sha256").update(u).digest("base64url"),p=Vs.randomBytes(16).toString("hex"),m=new URLSearchParams({response_type:"code",client_id:d,code_challenge:h,code_challenge_method:"S256",redirect_uri:c,state:p,resource:o}),f=i??r.scopes_supported;f?.length&&m.set("scope",f.join(" "));let g=new URL(r.authorization_endpoint);for(let[k,b]of m)g.searchParams.set(k,b);let w=g.toString();_i(w);let y=await l.waitForCode(p,18e4),v=await this.exchangeOAuthCode(r.token_endpoint,y,c,d,u);this.authManager?.storeOAuthToken(e,{accessToken:v.access_token,refreshToken:v.refresh_token,expiresAt:v.expires_in?Date.now()+v.expires_in*1e3:void 0,tokenEndpoint:r.token_endpoint,clientId:d,resource:o})}finally{l.close()}}async refreshProbeTokens(){if(!this.authManager)return;let e=this.authManager.getExpiringTokens();for(let[t,s]of e)if(s.refreshToken)try{let n=new URLSearchParams({grant_type:"refresh_token",refresh_token:s.refreshToken,client_id:s.clientId}).toString(),r=await this.oauthFetch(s.tokenEndpoint,"POST",n,"application/x-www-form-urlencoded");if(r.status===200){let i=JSON.parse(r.body),o=i.access_token;o&&this.authManager.storeOAuthToken(t,{accessToken:o,refreshToken:i.refresh_token??s.refreshToken,expiresAt:typeof i.expires_in=="number"?Date.now()+i.expires_in*1e3:void 0,tokenEndpoint:s.tokenEndpoint,clientId:s.clientId,resource:s.resource})}}catch(n){console.warn(`McpManager: failed to refresh token for ${t}:`,n)}}async discoverOAuthMetadata(e){let t=e.endsWith("/sse")?e.replace(/\/sse$/,"/mcp"):e,s=new URL(t),n;try{let u=await this.oauthFetch(t,"POST","{}","application/json");u.status===401&&(n=u.headers?.["www-authenticate"]?.match(/resource_metadata="([^"]+)"/)?.[1])}catch{}n||(n=`${s.origin}/.well-known/oauth-protected-resource${s.pathname}`);let r=s.origin,i,o=t;try{let u=await this.oauthFetch(n,"GET");if(u.status===200){let h=JSON.parse(u.body),p=h.authorization_servers;p?.[0]&&(r=p[0]),Array.isArray(h.scopes_supported)&&(i=h.scopes_supported),typeof h.resource=="string"&&(o=h.resource)}}catch{}let l=new URL(r),c=l.pathname==="/"?"":l.pathname,d=`${l.origin}/.well-known/oauth-authorization-server${c}`;try{let u=await this.oauthFetch(d,"GET");if(u.status===200)return{metadata:JSON.parse(u.body),resourceScopes:i,resource:o}}catch{}if(c){let u=`${l.origin}/.well-known/oauth-authorization-server`;try{let h=await this.oauthFetch(u,"GET");if(h.status===200)return{metadata:JSON.parse(h.body),resourceScopes:i,resource:o}}catch{}}return null}async registerOAuthClient(e,t){let s=JSON.stringify({client_name:"Agent Fleet Obsidian Plugin",redirect_uris:[t],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"}),n=await this.oauthFetch(e,"POST",s,"application/json");if(n.status!==200&&n.status!==201)throw new Error(`Client registration failed (HTTP ${n.status})`);let r=JSON.parse(n.body);if(!r.client_id)throw new Error("Client registration response missing client_id");return r.client_id}async startOAuthCallbackServer(){let e=null,t=null,s=Jn.createServer((r,i)=>{try{let o=new URL(r.url??"/","http://localhost");if(o.pathname!=="/callback"){i.writeHead(404),i.end();return}let l=o.searchParams.get("error");if(l){let u=o.searchParams.get("error_description")??l;i.writeHead(200,{"Content-Type":"text/html"}),i.end("<html><body style='font-family:system-ui;text-align:center;padding:60px'><h2>Authorization Failed</h2><p>"+u+"</p><p style='color:#888'>You can close this tab.</p></body></html>"),t?.(new Error(`OAuth denied: ${u}`));return}let c=o.searchParams.get("code"),d=o.searchParams.get("state");if(!c||!d){i.writeHead(400),i.end("Missing code or state");return}i.writeHead(200,{"Content-Type":"text/html"}),i.end("<html><body style='font-family:system-ui;text-align:center;padding:60px'><h2 style='color:#22c55e'>Authenticated!</h2><p>You can close this tab and return to Obsidian.</p><script>window.setTimeout(()=>window.close(),2000)</script></body></html>"),e?.(c,d)}catch(o){try{i.headersSent||i.writeHead(500),i.end()}catch{}t?.(o instanceof Error?o:new Error(String(o)))}});return{port:await new Promise((r,i)=>{s.listen(0,"127.0.0.1",()=>{let o=s.address();if(!o||typeof o=="string"){i(new Error("Failed to bind callback server"));return}r(o.port)}),s.on("error",i)}),waitForCode:(r,i)=>new Promise((o,l)=>{let c=window.setTimeout(()=>{l(new Error("Authentication timed out \u2014 complete authorization in your browser and try again."))},i);e=(d,u)=>{window.clearTimeout(c),u!==r?l(new Error("OAuth state mismatch \u2014 possible CSRF attack")):o(d)},t=d=>{window.clearTimeout(c),l(d)}}),close:()=>{try{s.closeAllConnections()}catch{}try{s.close()}catch{}}}}async exchangeOAuthCode(e,t,s,n,r){let i=new URLSearchParams({grant_type:"authorization_code",code:t,redirect_uri:s,client_id:n,code_verifier:r}).toString(),o=await this.oauthFetch(e,"POST",i,"application/x-www-form-urlencoded");if(o.status!==200)throw new Error(`Token exchange failed (HTTP ${o.status}): ${o.body}`);let l=JSON.parse(o.body);if(!l.access_token)throw new Error("Token response missing access_token");return l}oauthFetch(e,t,s,n){return new Promise((r,i)=>{let o=new URL(e),l=o.protocol==="https:",c={Accept:"application/json"};s&&(c["Content-Type"]=n??"application/json",c["Content-Length"]=String(Buffer.byteLength(s)));let d={hostname:o.hostname,port:o.port||(l?443:80),path:o.pathname+o.search,method:t,headers:c},h=(l?bo:Jn).request(d,m=>{let f="";m.on("data",g=>{f+=g.toString()}),m.on("end",()=>{let g={};for(let[w,y]of Object.entries(m.headers))typeof y=="string"?g[w]=y:Array.isArray(y)&&(g[w]=y.join(", "));r({status:m.statusCode??0,body:f,headers:g})})});h.on("error",i);let p=window.setTimeout(()=>{try{h.destroy()}catch{}i(new Error("OAuth request timed out"))},15e3);h.on("close",()=>window.clearTimeout(p)),s&&h.write(s),h.end()})}probeStdioServer(e,t){return new Promise(s=>{let n=t&&t.length>0?`${e} ${t.join(" ")}`:e,r=Ti(n,{env:{...process.env}}),i="",o,l=[],c=!1,d=!1,u=!1,h=()=>{c||(c=!0,r.kill(),s({description:o,tools:l}))},p=window.setTimeout(h,1e4);r.stdout.on("data",m=>{i+=m.toString();let f=re(i);i=f.pop()??"";for(let g of f){let w=g.trim();if(w){try{let y=JSON.parse(w);if(y.id===1&&y.result){o=y.result.instructions??y.result.serverInfo?.description,d=!0;try{r.stdin.write(JSON.stringify({jsonrpc:"2.0",method:"notifications/initialized"})+`
|
|
11902
|
+
`),r.stdin.write(JSON.stringify({jsonrpc:"2.0",id:2,method:"tools/list"})+`
|
|
11903
|
+
`)}catch{window.clearTimeout(p),h();return}}else if(y.id===2&&y.result){for(let v of y.result.tools??[])l.push({name:v.name,description:v.description,inputSchema:v.inputSchema});u=!0}}catch{}d&&u&&(window.clearTimeout(p),h())}}}),r.on("error",()=>{window.clearTimeout(p),h()}),r.on("close",()=>{window.clearTimeout(p),h()});try{r.stdin.write(JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"agent-fleet",version:"1.0.0"}}})+`
|
|
11904
|
+
`)}catch{window.clearTimeout(p),h()}})}async probeHttpServer(e){let t=await this.findServerToken(e);if(!t)return[];let s=e.url.endsWith("/sse")?e.url.replace(/\/sse$/,"/mcp"):e.url;try{let r=(await this.httpRequest(s,t,{jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-03-26",capabilities:{},clientInfo:{name:"agent-fleet",version:"1.0.0"}}}))?._sessionId;await this.httpRequest(s,t,{jsonrpc:"2.0",method:"notifications/initialized"},r);let i=await this.httpRequest(s,t,{jsonrpc:"2.0",id:2,method:"tools/list"},r),o=[],d=i?.result?.tools??[];for(let u of d)o.push({name:u.name,description:u.description,inputSchema:u.inputSchema});return o}catch(n){return console.warn(`McpManager: HTTP probe failed for ${e.name}:`,n),[]}}async findServerToken(e){if(this.authManager){let r=this.authManager.getToken(e.name);if(r)return r}let t=e.name.replace(/^claude\.ai\s+/i,"").replace(/\s+/g,"_").toUpperCase(),s=[`${t}_API_KEY`,`${t}_API_KEY_MILO`,`${t}_TOKEN`];for(let r of s){let i=process.env[r];if(i)return i}let n=[pr.join(qa(),".openclaw","workspace",".env"),pr.join(qa(),".env")];for(let r of n)try{let i=ko.readFileSync(r,"utf8");for(let o of re(i)){let l=o.trim().match(/^(?:export\s+)?([A-Za-z_]\w*)=(.*)$/);if(l){let c=l[1],d=l[2].replace(/^["']|["']$/g,"");if(s.includes(c))return d}}}catch{}}httpRequest(e,t,s,n){return new Promise((r,i)=>{let o=JSON.stringify(s),l=new URL(e),c=l.protocol==="https:",d={"Content-Type":"application/json",Accept:"application/json, text/event-stream",Authorization:`Bearer ${t}`,"Content-Length":String(Buffer.byteLength(o))};n&&(d["mcp-session-id"]=n);let u={hostname:l.hostname,port:l.port||(c?443:80),path:l.pathname+l.search,method:"POST",headers:d},p=(c?bo:Jn).request(u,f=>{let g="";f.on("data",w=>{g+=w.toString()}),f.on("end",()=>{let w=f.headers["mcp-session-id"];if((f.headers["content-type"]??"").includes("text/event-stream")){for(let v of re(g))if(v.startsWith("data: "))try{let k=JSON.parse(v.slice(6));w&&(k._sessionId=w),r(k);return}catch{}r(null)}else try{let v=JSON.parse(g);w&&(v._sessionId=w),r(v)}catch{r(null)}})});p.on("error",i);let m=window.setTimeout(()=>{p.destroy(),r(null)},15e3);p.on("close",()=>window.clearTimeout(m)),p.write(o),p.end()})}};var qd={"every 5m":"*/5 * * * *","every 10m":"*/10 * * * *","every 15m":"*/15 * * * *","every 30m":"*/30 * * * *","every 1h":"0 * * * *","every 2h":"0 */2 * * *",hourly:"0 * * * *","daily at 9am":"0 9 * * *","daily at 6pm":"0 18 * * *","weekdays at 9am":"0 9 * * 1-5","weekly on monday":"0 9 * * 1","monthly on 1st":"0 9 1 * *"},Qn=class{constructor(e,t){this.maxConcurrentRuns=e;this.callbacks=t}jobs=new Map;activeRuns=0;queue=[];paused=!1;setMaxConcurrentRuns(e){this.maxConcurrentRuns=e}parseSchedule(e){return qd[e.toLowerCase()]??e}toLocalISOString(e){let t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}async registerTask(e){if(this.unregisterTask(e.taskId),!(!e.enabled||e.type==="immediate"))try{if(e.type==="once"&&e.runAt){let t=new ie(new Date(e.runAt),{name:e.taskId,catch:!0},()=>{this.enqueue({task:e,reason:"scheduled"})});this.jobs.set(e.taskId,t),await this.callbacks.onTaskScheduled(e,e.runAt);return}if(e.type==="recurring"&&e.schedule){let t=this.parseSchedule(e.schedule),s=new ie(t,{name:e.taskId,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.enqueue({task:e,reason:"scheduled"})});this.jobs.set(e.taskId,s);let n=s.nextRun();await this.callbacks.onTaskScheduled(e,n?this.toLocalISOString(n):void 0)}}catch(t){console.error(`Agent Fleet: Failed to register task "${e.taskId}":`,t)}}unregisterTask(e){let t=this.jobs.get(e);t&&(t.stop(),this.jobs.delete(e))}async loadTasks(e){for(let t of e)await this.registerTask(t)}async handleStartupCatchUp(e){let t=Date.now();for(let s of e)!s.enabled||!s.catchUp||!s.nextRun||new Date(s.nextRun).getTime()<t&&await this.enqueue({task:s,reason:"catch-up"})}async enqueue(e){this.queue.push(e),await this.processQueue()}pauseAll(){this.paused=!0,this.jobs.forEach(e=>e.pause())}resumeAll(){this.paused=!1,this.jobs.forEach(e=>e.resume()),this.processQueue()}shutdown(){this.paused=!0,this.jobs.forEach(e=>e.stop()),this.jobs.clear(),this.queue.length=0}getQueueSize(){return this.queue.length}async processQueue(){if(!this.paused)for(;this.activeRuns<this.maxConcurrentRuns&&this.queue.length>0;){let e=this.queue.shift();if(!e)return;this.activeRuns+=1,this.callbacks.onTaskTriggered(e).finally(async()=>{this.activeRuns-=1,await this.processQueue()})}}};var Ys=class a{constructor(e,t,s){this.repository=e;this.settings=t;this.executor=new Kn(t,e,s),this.mcpManager=new Xn(t),s&&this.mcpManager.setAuthManager(s),this.memoryWriter=new fs(e),this.scheduler=new Qn(t.maxConcurrentRuns,{onTaskTriggered:n=>this.runPendingTask(n),onTaskScheduled:(n,r)=>this.repository.updateTaskRunMetadata(n,{nextRun:r})})}scheduler;executor;mcpManager;snapshot={agents:[],skills:[],tasks:[],channels:[],mcpServers:[],validationIssues:[]};runtimeState=new Map;recentRuns=[];chartRuns=[];static CHART_WINDOW_DAYS=14;recentUsage=[];statusChangeListeners=new Set;runOutputListeners=new Map;runOutputBuffers=new Map;runOutputPending=new Map;runOutputFlushTimers=new Map;static OUTPUT_FLUSH_INTERVAL_MS=100;fleetStatusCache=null;heartbeatJobs=new Map;reflectionJobs=new Map;reflectionsInFlight=new Set;reflectionRunning=0;reflectionWaiters=[];heartbeatRegisteredAt=0;heartbeatsInFlight=new Set;channelResultHandler;memoryWriter;async initialize(){this.snapshot=await this.repository.loadAll(),await this.repository.migrateAllLegacyMemory(),await this.refreshRunCaches();let e=this.snapshot.tasks.filter(t=>this.repository.getAgentByName(t.agent)?.enabled!==!1);await this.scheduler.loadTasks(e),await this.scheduler.handleStartupCatchUp(e),this.registerHeartbeats(),this.registerReflections(),this.emitStatusChange()}onChannelResult(e){this.channelResultHandler=e}async refreshFromVault(){this.snapshot=await this.repository.loadAll(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}getSnapshot(){return this.snapshot}getRecentRuns(){return this.recentRuns}getChartRuns(){return this.chartRuns}async refreshRunCaches(){this.recentRuns=await this.repository.listRecentRuns();let e=new Date;e.setDate(e.getDate()-(a.CHART_WINDOW_DAYS-1)),this.chartRuns=await this.repository.listRunsSince(e),this.recentUsage=await this.repository.readUsageSince(e)}getUsageRecords(){return this.recentUsage}recordUsage(e){this.recentUsage.push(e),this.repository.appendUsage(e).catch(t=>{console.warn("Agent Fleet: failed to append usage record",t)}),this.emitStatusChange()}getAgentState(e){let t=this.runtimeState.get(e),s=this.snapshot.agents.find(n=>n.name===e);return s&&!s.enabled?{status:"disabled",lastRun:t?.lastRun,currentRunId:t?.currentRunId}:t??{status:"idle"}}getFleetStatus(){let e=new Date,t=i=>String(i).padStart(2,"0"),s=`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`,n=this.fleetStatusCache;if(!n||n.runs!==this.recentRuns||n.today!==s){let i=this.recentRuns.filter(l=>{let c=new Date(l.started);return`${c.getFullYear()}-${t(c.getMonth()+1)}-${t(c.getDate())}`===s}).length,o=this.recentRuns.flatMap(l=>l.approvals??[]).filter(l=>l.status==="pending").length;n={runs:this.recentRuns,today:s,completedToday:i,pending:o},this.fleetStatusCache=n}return{running:Array.from(this.runtimeState.values()).filter(i=>i.status==="running").length,pending:n.pending,completedToday:n.completedToday}}subscribe(e){return this.statusChangeListeners.add(e),()=>this.statusChangeListeners.delete(e)}onRunOutput(e,t){this.flushRunOutput(e);let s=this.runOutputListeners.get(e);s||(s=new Set,this.runOutputListeners.set(e,s)),s.add(t);let n=this.runOutputBuffers.get(e);return n&&t(n),()=>{this.runOutputListeners.get(e)?.delete(t)}}getRunOutputBuffer(e){return this.runOutputBuffers.get(e)??""}emitRunOutput(e,t){this.runOutputBuffers.set(e,(this.runOutputBuffers.get(e)??"")+t),this.runOutputPending.set(e,(this.runOutputPending.get(e)??"")+t),this.runOutputFlushTimers.has(e)||this.runOutputFlushTimers.set(e,setTimeout(()=>this.flushRunOutput(e),a.OUTPUT_FLUSH_INTERVAL_MS))}flushRunOutput(e){let t=this.runOutputFlushTimers.get(e);t!==void 0&&(clearTimeout(t),this.runOutputFlushTimers.delete(e));let s=this.runOutputPending.get(e);if(!s)return;this.runOutputPending.delete(e);let n=this.runOutputListeners.get(e);if(n)for(let r of n)r(s)}resetRunOutput(e){let t=this.runOutputFlushTimers.get(e);t!==void 0&&(clearTimeout(t),this.runOutputFlushTimers.delete(e)),this.runOutputPending.delete(e),this.runOutputBuffers.set(e,"")}clearRunOutput(e){this.flushRunOutput(e),this.runOutputBuffers.delete(e),this.runOutputListeners.delete(e)}async handleVaultChange(e){await this.repository.loadFile(e),this.snapshot=this.repository.getSnapshot(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}async handleVaultDelete(e){this.repository.removeFile(e),this.snapshot=this.repository.getSnapshot(),await this.rebuildSchedules(),await this.refreshRunCaches(),this.emitStatusChange()}abortedAgents=new Set;abortAgentRun(e){let t=this.executor.abortAgent(e);return t&&(this.abortedAgents.add(e),this.runtimeState.set(e,{status:"idle"}),this.emitStatusChange()),t}wasAborted(e){return this.abortedAgents.has(e)}consumeAborted(e){let t=this.abortedAgents.has(e);return this.abortedAgents.delete(e),t}async runTaskNow(e,t){await this.scheduler.enqueue({task:{...e,type:"immediate"},reason:"manual",promptOverride:t})}async runAgentNow(e,t){let s=e.heartbeatBody.trim()&&t==="Run now and summarize the current state."?e.heartbeatBody.trim():t,n=s===e.heartbeatBody.trim()&&e.heartbeatBody.trim().length>0,r={filePath:"",taskId:n?`heartbeat-${Date.now()}`:`manual-${Date.now()}`,agent:e.name,type:"immediate",priority:"medium",enabled:!0,created:new Date().toISOString(),runCount:0,catchUp:!1,tags:n?[...e.tags,"heartbeat"]:e.tags,body:s};await this.scheduler.enqueue({task:r,reason:n?"heartbeat":"manual",promptOverride:s})}async resolveApproval(e,t,s){e.filePath&&(await this.repository.setApprovalDecision(e.filePath,t,s),await this.refreshRunCaches(),this.emitStatusChange())}async pruneOldRuns(){let e=Date.now()-this.settings.runLogRetentionDays*24*60*60*1e3,t=await this.repository.listRecentRuns(500);for(let s of t)s.filePath&&new Date(s.started).getTime()<e&&await this.repository.trashFile(s.filePath)}async rebuildSchedules(){this.scheduler.pauseAll();for(let e of this.snapshot.tasks)this.scheduler.unregisterTask(e.taskId);this.scheduler.setMaxConcurrentRuns(this.settings.maxConcurrentRuns),await this.scheduler.loadTasks(this.snapshot.tasks.filter(e=>this.repository.getAgentByName(e.agent)?.enabled!==!1)),this.scheduler.resumeAll(),this.registerHeartbeats(),this.registerReflections()}shutdown(){for(let[,e]of this.heartbeatJobs)e.stop();this.heartbeatJobs.clear(),this.heartbeatsInFlight.clear();for(let[,e]of this.reflectionJobs)e.stop();this.reflectionJobs.clear(),this.reflectionsInFlight.clear();for(let[,e]of this.runOutputFlushTimers)clearTimeout(e);this.runOutputFlushTimers.clear(),this.runOutputPending.clear(),this.scheduler.shutdown()}registerHeartbeats(){for(let[,e]of this.heartbeatJobs)e.stop();this.heartbeatJobs.clear(),this.heartbeatRegisteredAt=Date.now();for(let e of this.snapshot.agents)if(!(!e.enabled||!e.heartbeatEnabled||!e.heartbeatSchedule.trim()||!e.heartbeatBody.trim()))try{let t=new ie(e.heartbeatSchedule,{name:`heartbeat:${e.name}`,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.runHeartbeat(e.name)});this.heartbeatJobs.set(e.name,t)}catch(t){console.error(`Agent Fleet: failed to register heartbeat for "${e.name}":`,t)}}async runHeartbeat(e){if(Date.now()-this.heartbeatRegisteredAt<1e4||this.heartbeatsInFlight.has(e))return;this.heartbeatsInFlight.add(e);let t=!1;try{let s=this.repository.getAgentByName(e);if(!s||!s.enabled||!s.heartbeatBody.trim())return;let n={filePath:"",taskId:`heartbeat-${Date.now()}`,agent:s.name,type:"immediate",priority:"medium",enabled:!0,created:new Date().toISOString(),runCount:0,catchUp:!1,tags:[...s.tags,"heartbeat"],body:s.heartbeatBody.trim()};await this.scheduler.enqueue({task:n,reason:"heartbeat",promptOverride:s.heartbeatBody.trim()}),t=!0}finally{t||this.heartbeatsInFlight.delete(e)}}getNextHeartbeat(e){let t=this.heartbeatJobs.get(e);return t?t.nextRun()??null:null}registerReflections(){for(let[,e]of this.reflectionJobs)e.stop();this.reflectionJobs.clear();for(let e of this.snapshot.agents){if(!e.enabled||!e.memory||!e.reflection.enabled)continue;let t=e.reflection.schedule.trim();if(t)try{let s=new ie(t,{name:`reflection:${e.name}`,catch:!0,protect:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone},()=>{this.runReflection(e.name)});this.reflectionJobs.set(e.name,s)}catch(s){console.error(`Agent Fleet: failed to register reflection for "${e.name}":`,s)}}}getNextReflection(e){return this.reflectionJobs.get(e)?.nextRun()??null}async runReflectionNow(e){return this.runReflection(e)}async listPendingProposals(){return(await this.repository.listProposals()).filter(t=>t.status==="pending")}async acceptProposal(e){let t=await this.repository.readProposal(e);if(!t)return{ok:!1,message:"Proposal not found."};try{let s=await this.repository.applyProposal(t);return s?(await this.repository.setProposalStatus(e,"accepted"),await this.refreshFromVault(),{ok:!0,message:`Applied \u2192 ${s}`}):{ok:!1,message:"Couldn't apply \u2014 target skill not found; proposal left pending."}}catch(s){return{ok:!1,message:`Failed to apply: ${s instanceof Error?s.message:String(s)}`}}}async rejectProposal(e){await this.repository.setProposalStatus(e,"rejected"),this.emitStatusChange()}async withReflectionSlot(e){let t=Math.max(1,this.settings.maxConcurrentRuns);this.reflectionRunning>=t?await new Promise(s=>this.reflectionWaiters.push(s)):this.reflectionRunning++;try{return await e()}finally{let s=this.reflectionWaiters.shift();s?s():this.reflectionRunning--}}async runReflection(e){let t=this.repository.getAgentByName(e);if(!t||!t.enabled||!t.memory)return{ok:!1,message:"Agent not found, disabled, or memory off."};if(this.reflectionsInFlight.has(e))return{ok:!1,message:"A reflection is already in progress."};this.reflectionsInFlight.add(e);let s=new Date().toISOString(),n=s,r=`reflection-${Date.now()}`;this.runtimeState.set(e,{status:"running",currentTaskId:r,runStarted:s}),this.resetRunOutput(e),this.emitStatusChange();try{await this.repository.migrateLegacyMemory(e);let i=await this.repository.readWorkingMemory(e),o=i?at(i.sections):"",l=await this.repository.readRecentRaw(e,2),c=yo({agentName:e,workingMemoryBody:o,recentRaw:l,tokenBudget:t.memoryTokenBudget}),d={filePath:"",taskId:r,agent:t.name,type:"immediate",priority:"low",enabled:!0,created:n,runCount:0,catchUp:!1,tags:[...t.tags,"reflection"],body:c,model:t.reflection.model||void 0},u=await this.withReflectionSlot(()=>this.executor.execute(t,d,c,y=>this.emitRunOutput(e,y),{suppressMemoryCapture:!0})),h=vo(u.outputText),p=await this.memoryWriter.reflect(t,h.sections,n);if(h.candidates.length>0){let y=await this.repository.readCandidates(e),v=wo(y,h.candidates,n);await this.repository.writeCandidates(e,v),await this.generateProposals(t,v,n)}let m=p?"Reflection complete \u2014 working memory consolidated.":"Reflection produced no memory block; working memory left unchanged.",f=u.exitCode===0||u.exitCode===null?"success":"failure",g={runId:u.runId,agent:t.name,task:r,status:f,started:s,completed:new Date().toISOString(),durationSeconds:u.durationSeconds,tokensUsed:u.tokensUsed,costUsd:u.costUsd,model:u.resolvedModel||t.reflection.model||t.model,modelSource:u.modelSource,concreteModel:u.concreteModel,exitCode:u.exitCode,tags:Array.from(new Set([...t.tags,"reflection"])),prompt:u.prompt,output:u.outputText,toolsUsed:u.toolsUsed.map(y=>`${y.tool}${y.command?`: ${y.command}`:""}`),finalResult:m,stderr:u.stderr},w=await this.repository.writeRunLog(g);return await this.refreshRunCaches(),this.runtimeState.set(e,{status:f==="success"?"idle":"error",currentRunId:u.runId,lastRun:{...g,filePath:w}}),f==="failure"&&this.notify(g),{ok:p,message:m}}catch(i){let o=i instanceof Error?i.message:String(i);console.warn(`Agent Fleet: reflection failed for "${e}":`,i);let l={runId:(0,mr.randomUUID)(),agent:e,task:r,status:"failure",started:s,completed:new Date().toISOString(),durationSeconds:Math.round((Date.now()-new Date(s).getTime())/1e3),model:t.reflection.model||t.model,exitCode:1,tags:Array.from(new Set([...t.tags,"reflection"])),prompt:"",output:`Reflection failed: ${o}`,toolsUsed:[]},c=l;try{let d=await this.repository.writeRunLog(l);await this.refreshRunCaches(),c={...l,filePath:d}}catch(d){console.warn(`Agent Fleet: failed to write reflection run log for "${e}"`,d)}return this.runtimeState.set(e,{status:"error",lastRun:c}),this.notify(l),{ok:!1,message:`Reflection failed: ${o}`}}finally{this.reflectionsInFlight.delete(e),this.clearRunOutput(e),this.emitStatusChange()}}async generateProposals(e,t,s){if(!e.reflection.proposeSkills)return;let n=e.reflection.recurrenceThreshold||3;for(let r of t){if(r.proposed||r.occurrences<n)continue;let o={id:`prop-${s.slice(0,10)}-${r.key}`.slice(0,80),type:"skill_create",agent:e.name,status:"pending",created:s,targetSkill:r.suggestedSkill||r.key,candidate:r.key,evidence:r.evidence,rationale:r.pattern,body:`This skill was proposed by reflection because the following friction recurred ${r.occurrences} times:
|
|
11903
11905
|
|
|
11904
|
-
> ${
|
|
11906
|
+
> ${r.pattern}
|
|
11905
11907
|
|
|
11906
|
-
Document the reliable steps to handle this so future runs don't rediscover them.`};try{await this.repository.writeProposal(o),a.proposed=!0,await this.repository.writeCandidates(t.name,e)}catch(c){console.warn(`Agent Fleet: failed to write proposal for "${t.name}"`,c)}}}async runPendingTask({task:t,promptOverride:e}){let s=this.repository.getAgentByName(t.agent);if(!s||!s.enabled)return;let n=new Date().toISOString();this.runtimeState.set(s.name,{status:"running",currentTaskId:t.taskId,runStarted:n}),this.runOutputBuffers.set(s.name,""),this.emitStatusChange();try{let a=await this.executor.execute(s,t,e,m=>{let f=this.runOutputBuffers.get(s.name)??"";this.runOutputBuffers.set(s.name,f+m);let g=this.runOutputListeners.get(s.name);if(g)for(let y of g)y(m)}),i=this.consumeAborted(s.name),o=i?[]:this.buildApprovals(s,a.toolsUsed),c=i?"cancelled":this.resolveRunStatus(a,o),l={runId:a.runId,agent:s.name,task:t.taskId,status:c,started:n,completed:new Date().toISOString(),durationSeconds:a.durationSeconds,tokensUsed:a.tokensUsed,costUsd:a.costUsd,model:a.resolvedModel||s.model,modelSource:a.modelSource,concreteModel:a.concreteModel,exitCode:a.exitCode,tags:Array.from(new Set([...s.tags,...t.tags])),prompt:a.prompt,output:a.outputText,toolsUsed:a.toolsUsed.map(m=>`${m.tool}${m.command?`: ${m.command}`:""}`),finalResult:a.finalResult,stderr:a.stderr,approvals:o},h=await this.repository.writeRunLog(l);if(await this.repository.updateTaskRunMetadata(t,{lastRun:n,runCount:t.runCount+1}),s.memory){let f=t.tags.includes("heartbeat")?"heartbeat":`task:${t.taskId}`,g=qs(a.outputText);try{await this.memoryWriter.capture(s,g,f,new Date().toISOString())}catch(y){console.warn(`Agent Fleet: failed to append memory for "${s.name}"`,y)}}let d=t.tags.includes("heartbeat"),u=d?s.heartbeatChannel:t.channel??"",p=d?s.heartbeatChannelTarget??"":t.channelTarget??"";if(u&&!i&&l.output.trim())try{this.channelResultHandler?.(s.name,u,l.output,d?"heartbeat":t.taskId,p)}catch(m){console.warn(`Agent Fleet: channel delivery failed for ${s.name}`,m)}i&&(l.output="Task was manually stopped."),await this.refreshRunCaches(),this.runtimeState.set(s.name,{status:i||c==="success"?"idle":c==="pending_approval"?"pending":"error",currentRunId:a.runId,lastRun:{...l,filePath:h}}),i||this.notify(l)}catch(a){let i=this.consumeAborted(s.name),o=i?"cancelled":"failure",c=It(t,s,this.settings),l={runId:(0,Sa.randomUUID)(),agent:s.name,task:t.taskId,status:o,started:n,completed:new Date().toISOString(),durationSeconds:Math.round((Date.now()-new Date(n).getTime())/1e3),model:c.value||s.model,modelSource:c.source,exitCode:i?-1:1,tags:Array.from(new Set([...s.tags,...t.tags])),prompt:e??t.body,output:i?"Task was manually stopped.":a instanceof Error?a.message:String(a),toolsUsed:[]},h=await this.repository.writeRunLog(l);await this.refreshRunCaches(),this.runtimeState.set(s.name,{status:i?"idle":"error",lastRun:{...l,filePath:h}}),i||this.notify(l)}finally{if(s.memory)try{await this.memoryWriter.drainPending(s,new Date().toISOString())}catch(a){console.warn(`Agent Fleet: failed to drain pending memory for "${s.name}"`,a)}this.runOutputBuffers.delete(s.name),this.runOutputListeners.delete(s.name),this.emitStatusChange()}}buildApprovals(t,e){let s=e.filter(n=>t.approvalRequired.includes(n.tool)).map(n=>({tool:n.tool,command:n.command,reason:n.reason,status:"pending"}));return s.length>0?s:void 0}resolveRunStatus(t,e){return e?.length?"pending_approval":t.timedOut?"timeout":t.exitCode===0?"success":"failure"}notify(t){if(this.settings.notificationLevel==="none"||this.settings.notificationLevel==="failures-only"&&t.status==="success")return;let s=(ye(t.output).map(a=>a.trim()).find(a=>a&&!a.startsWith("{")&&!a.startsWith("["))??"").slice(0,120)||t.status,n=t.status==="success"?`\u2705 ${t.agent}: ${s}`:t.status==="pending_approval"?`\u{1F535} ${t.agent} needs approval: ${(t.approvals??[])[0]?.tool??"tool action"}`:`\u274C ${t.agent}: ${s}`;new wi.Notice(n,t.status==="success"?5e3:0)}emitStatusChange(){for(let t of this.statusChangeListeners)t()}};function uc(r){return r.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-{2,}/g,"-").replace(/^-|-$/g,"")}function xs(r,t){return`${r}-${uc(t)}`}var Vt="af-channel-cred",Ss="af-mcp-secret",fn=class{constructor(t){this.storage=t;t||console.warn("Agent Fleet: SecretStorage unavailable (Obsidian < 1.11.4). Secrets will use plaintext fallback.")}get available(){return!!this.storage}setJson(t,e,s){if(!this.storage)return;let n=xs(t,e);this.storage.setSecret(n,JSON.stringify(s))}getJson(t,e){if(!this.storage)return null;let s=xs(t,e),n=this.storage.getSecret(s);if(!n)return null;try{return JSON.parse(n)}catch{return null}}setString(t,e,s){if(!this.storage)return;let n=xs(t,e);this.storage.setSecret(n,s)}getString(t,e){if(!this.storage)return null;let s=xs(t,e);return this.storage.getSecret(s)||null}delete(t,e){if(!this.storage)return;let s=xs(t,e);this.storage.setSecret(s,"")}listByPrefix(t){return this.storage?this.storage.listSecrets().filter(e=>e.startsWith(t+"-")):[]}};var gn=class{tokens=new Map;oauthTokens=new Map;secretStore;setSecretStore(t){this.secretStore=t}storeProbeToken(t,e){this.tokens.set(t,e)}storeStaticToken(t,e){this.tokens.set(t,e),this.secretStore?.setJson(Ss,t,{accessToken:e})}storeOAuthToken(t,e){this.oauthTokens.set(t,e),this.tokens.set(t,e.accessToken),this.secretStore?.setJson(Ss,t,{accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,tokenEndpoint:e.tokenEndpoint,clientId:e.clientId,resource:e.resource})}hydrate(t){if(!this.secretStore)return null;let e=this.secretStore.getJson(Ss,t);return e?.accessToken?(this.tokens.set(t,e.accessToken),e.tokenEndpoint&&e.clientId&&e.resource&&this.oauthTokens.set(t,{accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,tokenEndpoint:e.tokenEndpoint,clientId:e.clientId,resource:e.resource}),e):null}getToken(t){return this.tokens.get(t)??this.hydrate(t)?.accessToken??void 0}getOAuthToken(t){return this.oauthTokens.has(t)?this.oauthTokens.get(t):(this.hydrate(t),this.oauthTokens.get(t))}hasToken(t){return this.tokens.has(t)||!!this.hydrate(t)}removeToken(t){this.tokens.delete(t),this.oauthTokens.delete(t),this.secretStore?.delete(Ss,t)}getExpiringTokens(t=5*6e4){let e=new Map,s=Date.now();for(let[n,a]of this.oauthTokens)a.refreshToken&&a.expiresAt&&a.expiresAt-s<t&&e.set(n,a);return e}};var ut=require("obsidian");var yn=require("crypto"),ot=require("obsidian");function Cs(){return(0,yn.randomUUID)()}function bi(r){let t=`${r.timestamp}|${r.content.slice(0,80)}`;return(0,yn.createHash)("sha1").update(t).digest("hex").slice(0,16)}var Yt=class r{constructor(t,e,s,n,a){this.agent=t;this.settings=e;this.repository=s;this.vault=n,this.channelName=a?.channelName,this.conversationId=a?.conversationId,this.channelContext=a?.channelContext,this.inAppConversationId=a?.inAppConversationId,this.threadAnchorId=a?.threadAnchorId,this.parentSession=a?.parentSession,this.mcpAuth=a?.mcpAuth,this.memoryWriter=new Gt(s)}messages=[];isStreaming=!1;isProcessAlive=!1;settingsState=null;mcpProjection=null;get pendingTurnCount(){return this.pendingTurns}lastActiveAt=Date.now();process=null;claudeSessionId=null;claudeResumeAttempted=!1;vault;stdoutBuffer="";processListeners=null;basePromptSent=!1;codexTurnState=null;codexQueue=[];codexResumeAttempted=!1;codexTurnErrors=[];codexStderr="";codexPermState=null;get isCodex(){return kt(this.agent.adapter)==="codex"}channelName;conversationId;channelContext;inAppConversationId;conversationName="";threadAnchorId;parentSession;threadAnchorIndex;threads=new Map;threadIndex={};activeOnEvent=null;turnResponseText="";displayedLen=0;turnToolCalls=[];pendingTurns=0;turnResolve=null;turnReject=null;needsCompactBeforeNextTurn=!1;lastCompactTriggerAt=0;static WATCHDOG_FALLBACK_MINUTES=10;watchdogTimer=null;getWatchdogMs(){let t=this.settings.chatWatchdogMinutes;return(typeof t=="number"&&t>0?t:r.WATCHDOG_FALLBACK_MINUTES)*60*1e3}armWatchdog(){this.clearWatchdog();let t=this.getWatchdogMs();this.watchdogTimer=window.setTimeout(()=>{if(this.watchdogTimer=null,!this.isStreaming)return;this.activeOnEvent?.({type:"error",content:"",errorMessage:`no response from the CLI for ${Math.round(t/6e4)} minutes \u2014 giving up`});let e=new Error("Watchdog timeout");this.handleProcessError(e);try{this.process?.kill()}catch{}},t)}clearWatchdog(){this.watchdogTimer&&(window.clearTimeout(this.watchdogTimer),this.watchdogTimer=null)}currentToolName;activityListeners=new Set;onActivityChange(t){return this.activityListeners.add(t),t(),()=>{this.activityListeners.delete(t)}}emitActivity(){for(let t of this.activityListeners)t()}setStreaming(t){this.isStreaming!==t&&(this.isStreaming=t,t||(this.currentToolName=void 0),this.emitActivity())}setCurrentTool(t){this.currentToolName!==t&&(this.currentToolName=t,this.emitActivity())}stats={costTotalUsd:0,turnCount:0};usageRecorder;lastResultCostUsd=0;setUsageRecorder(t){this.usageRecorder=t}statsListeners=new Set;onStatsChange(t){return this.statsListeners.add(t),t({...this.stats}),()=>{this.statsListeners.delete(t)}}getStats(){return{...this.stats}}emitStats(){let t={...this.stats};for(let e of this.statsListeners)e(t)}mcpAuth;buildMcpProjection(t){let e=this.agent.memory?this.repository.getPendingDirAbsolutePath(this.agent.name):null,s=cn({registry:this.repository.getMcpServers(),agentGrants:this.agent.mcpServers??[],getBearerToken:n=>this.mcpAuth?.getToken(n),remember:e?{pendingDir:e,source:`mcp:${this.captureSource()}`}:null});return this.mcpProjection=dn(t,this.agent.adapter,s),{args:this.mcpProjection?.args??[],env:this.mcpProjection?.env??{},allowServers:s.map(n=>n.def.name)}}memoryWriter;captureSource(){return`chat:${this.inAppConversationId||this.conversationId||"default"}`}getConversationName(){return this.conversationName}async setConversationName(t){this.conversationName=t,await this.persist()}refreshAgent(){let t=this.repository.getAgentByName(this.agent.name);t&&(this.agent=t)}get isThread(){return!!this.threadAnchorId}async loadPersistedState(){let t=this.getChatFilePath(),e=this.vault.getAbstractFileByPath(t);if(!(e instanceof ot.TFile))return!1;try{let s=await this.vault.cachedRead(e);if(this.isThread){let a=JSON.parse(s);return a.messages?.length>0||a.sessionId?(this.messages=(a.messages??[]).map(i=>i.id?i:{...i,id:bi(i)}),this.claudeSessionId=a.sessionId??null,this.threadAnchorIndex=a.anchorIndex,this.claudeSessionId&&(this.basePromptSent=!0),!0):!1}let n=JSON.parse(s);if(n.name&&(this.conversationName=n.name),n.messages?.length>0)return this.messages=n.messages.map(a=>a.id?a:{...a,id:bi(a)}),this.claudeSessionId=n.sessionId??null,this.threadIndex=n.threads??{},this.claudeSessionId&&(this.basePromptSent=!0),!0}catch{}return!1}getThreadIndex(){return{...this.threadIndex}}async persist(){let t=new Date().toISOString(),e=this.getChatFilePath(),s;if(this.isThread){let a={anchorMessageId:this.threadAnchorId,anchorIndex:this.threadAnchorIndex??0,sessionId:this.claudeSessionId,messages:this.messages,createdAt:this.parentSession?.threadIndex[this.threadAnchorId]?.createdAt??t,lastActive:t};s=JSON.stringify(a,null,2)}else{let a={sessionId:this.claudeSessionId,messages:this.messages,lastActive:t,name:this.conversationName||void 0,threads:Object.keys(this.threadIndex).length>0?this.threadIndex:void 0};s=JSON.stringify(a,null,2)}let n=this.vault.getAbstractFileByPath(e);n instanceof ot.TFile?await this.vault.modify(n,s):(await this.ensureParentFolders(e),await this.vault.create(e,s)),this.isThread&&this.parentSession&&this.threadAnchorId&&await this.parentSession.upsertThreadIndex(this.threadAnchorId,{path:e,createdAt:this.parentSession.threadIndex[this.threadAnchorId]?.createdAt??t,messageCount:this.messages.length,lastActive:t})}async upsertThreadIndex(t,e){this.threadIndex[t]=e,await this.persist()}async ensureParentFolders(t){let e=t.lastIndexOf("/");if(e<=0)return;let n=t.slice(0,e).split("/"),a="";for(let i of n)if(a=a?`${a}/${i}`:i,!this.vault.getAbstractFileByPath(a))try{await this.vault.createFolder(a)}catch(o){if(!(o instanceof Error?o.message:String(o)).includes("already exists"))throw o}}async clearPersistedState(){let t=this.getChatFilePath();await this.repository.trashFile(t),this.messages=[],this.claudeSessionId=null,this.basePromptSent=!1}getChatFilePath(){if(this.threadAnchorId&&this.parentSession)return this.parentSession.getThreadFilePath(this.threadAnchorId);if(this.channelName&&this.conversationId){let s=this.settings.fleetFolder,n=oe(this.conversationId)||"conversation";return(0,ot.normalizePath)(`${s}/channels/${this.channelName}/sessions/${n}.json`)}if(!this.inAppConversationId)throw new Error("ChatSession requires inAppConversationId (or channel options) to resolve a file path");let t=oe(this.inAppConversationId)||"conversation";if(this.agent.isFolder){let s=this.agent.filePath.replace(/\/agent\.md$/,"");return(0,ot.normalizePath)(`${s}/conversations/${t}.json`)}let e=this.repository.getMemoryPath(this.agent.name).replace(/\/[^/]+$/,"");return(0,ot.normalizePath)(`${e}/${this.agent.name}-conversations/${t}.json`)}getThreadFilePath(t){let e=this.getParentChatFilePath(),s=e.replace(/\/[^/]+$/,""),n=e.slice(s.length+1).replace(/\.json$/,"");return(0,ot.normalizePath)(`${s}/${n}.threads/${t}.json`)}getParentChatFilePath(){if(this.channelName&&this.conversationId){let t=this.settings.fleetFolder,e=oe(this.conversationId)||"conversation";return(0,ot.normalizePath)(`${t}/channels/${this.channelName}/sessions/${e}.json`)}if(this.inAppConversationId){let t=oe(this.inAppConversationId)||"conversation";if(this.agent.isFolder){let s=this.agent.filePath.replace(/\/agent\.md$/,"");return(0,ot.normalizePath)(`${s}/conversations/${t}.json`)}let e=this.repository.getMemoryPath(this.agent.name).replace(/\/[^/]+$/,"");return(0,ot.normalizePath)(`${e}/${this.agent.name}-conversations/${t}.json`)}throw new Error("ChatSession requires inAppConversationId (or channel options) to resolve a parent file path")}async ensureProcess(){if(this.process&&this.isProcessAlive)return;this.refreshAgent();let t=["--input-format","stream-json","--output-format","stream-json","--verbose"];this.claudeSessionId?(t.push("--resume",this.claudeSessionId),this.basePromptSent=!0,this.claudeResumeAttempted=!0):this.claudeResumeAttempted=!1;let e=It(null,this.agent,this.settings);ws(e.value)&&t.push("--model",e.value);let s=this.agent.permissionMode?.trim();s&&s!=="default"?t.push("--permission-mode",s):t.push("--permission-mode","bypassPermissions"),this.agent.effort&&t.push("--effort",this.agent.effort);let n=this.agent.cwd?.trim()?this.agent.cwd:this.repository.getVaultBasePath()??".",a=this.buildMcpProjection(n);t.push(...a.args),this.settingsState=sn(n,this.agent,{mcpAllowServers:a.allowServers});let i=dt(this.settings.claudeCliPath,t,{cwd:n,env:{...process.env,AWS_REGION:this.settings.awsRegion,...a.env}});this.process=i,this.isProcessAlive=!0,this.stdoutBuffer="",this.lastResultCostUsd=0,this.processListeners={onStdout:o=>this.handleStdout(o),onStderr:()=>{},onError:o=>this.handleProcessError(o),onClose:()=>this.handleProcessClose()},i.stdout.on("data",this.processListeners.onStdout),i.stderr.on("data",this.processListeners.onStderr),i.on("error",this.processListeners.onError),i.on("close",this.processListeners.onClose)}detachProcessListeners(){this.process&&this.processListeners&&(this.process.stdout?.removeListener("data",this.processListeners.onStdout),this.process.stderr?.removeListener("data",this.processListeners.onStderr),this.process.removeListener("error",this.processListeners.onError),this.process.removeListener("close",this.processListeners.onClose)),this.processListeners=null}handleStdout(t){this.isStreaming&&this.armWatchdog(),this.stdoutBuffer+=t.toString();let e=ye(this.stdoutBuffer);this.stdoutBuffer=e.pop()??"";for(let s of e){let n=s.trim();if(n)try{let a=JSON.parse(n);this.handleEvent(a)}catch{}}}handleEvent(t){if(this.isCodex){this.handleCodexEvent(t);return}if(typeof t.session_id=="string"&&(this.claudeSessionId=t.session_id),this.updateStatsFromEvent(t),t.type==="system"&&t.subtype==="compact_boundary"){let s=t.compact_metadata,n=s&&typeof s.pre_tokens=="number"?s.pre_tokens:0,a=s&&typeof s.post_tokens=="number"?s.post_tokens:0;a>0&&(this.stats.contextTokensUsed=a),this.stats.lastCompact={preTokens:n,postTokens:a},this.emitStats(),this.needsCompactBeforeNextTurn=!1,this.activeOnEvent?.({type:"compacted",content:"",compact:{preTokens:n,postTokens:a}});return}if(t.type==="result"){let s=typeof t.api_error_status=="string"&&!!t.api_error_status;if(t.is_error===!0||s){let n=this.describeResultError(t);this.activeOnEvent?.({type:"error",content:"",errorMessage:n}),this.claudeResumeAttempted&&t.is_error===!0&&!s&&this.clearSessionId()}this.handleTurnEnd();return}let e=this.parseStreamEvent(t);e&&this.dispatchStreamEvent(e)}dispatchStreamEvent(t){let e=t;if(t.type==="text"){let s=this.turnResponseText.length===0;if(s&&(this.displayedLen=0),this.turnResponseText+=t.content,this.setCurrentTool(void 0),s&&this.turnResponseText.length>0&&this.emitActivity(),this.agent.memory){let n=ur(this.turnResponseText),a=n.length>this.displayedLen?n.slice(this.displayedLen):"";this.displayedLen=n.length,e={...t,content:a}}}else t.type==="tool_use"&&t.toolName&&(this.turnToolCalls.push({name:t.toolName,command:t.content||void 0}),this.setCurrentTool(t.toolName));this.activeOnEvent?.(e)}handleCodexEvent(t){this.codexTurnState||(this.codexTurnState=ya());let e=ri(t,this.codexTurnState);for(let s of e)switch(s.kind){case"session":this.claudeSessionId=s.sessionId;break;case"text":this.dispatchStreamEvent({type:"text",content:s.text});break;case"tool":this.dispatchStreamEvent({type:"tool_use",content:s.command?s.command.slice(0,150):"",toolName:s.toolName});break;case"usage":{s.contextTokens>0&&s.contextTokens!==this.stats.contextTokensUsed&&(this.stats.contextTokensUsed=s.contextTokens),this.stats.turnCount+=1,this.emitStats();break}case"turn-failed":case"error":this.codexTurnErrors.push(s.message),this.activeOnEvent?.({type:"error",content:"",errorMessage:s.message});break}}get hasCurrentTurnText(){return this.turnResponseText.length>0}describeResultError(t){let e=[],s=typeof t.api_error_status=="string"?t.api_error_status:"",n=typeof t.subtype=="string"?t.subtype:"",a=typeof t.result=="string"?t.result:"";return s?e.push(`API ${s}`):n?e.push(n.replace(/_/g," ")):e.push("unknown error"),a&&e.push(`\u2014 ${a}`),e.join(" ")}updateStatsFromEvent(t){let e=!1,s=typeof t.model=="string"?t.model:void 0,n=t.message,a=n&&typeof n.model=="string"?n.model:void 0,i=s||a;if(i&&i!==this.stats.concreteModel&&(this.stats.concreteModel=i,e=!0),t.type==="rate_limit_event"){let o=t.rate_limit_info;o&&(this.stats.rateLimit={type:typeof o.rateLimitType=="string"?o.rateLimitType:"unknown",resetsAt:typeof o.resetsAt=="number"?o.resetsAt:void 0,status:typeof o.status=="string"?o.status:void 0,isUsingOverage:typeof o.isUsingOverage=="boolean"?o.isUsingOverage:void 0},e=!0)}if(t.type==="assistant"&&n){let o=n.usage;if(o){let c=typeof o.input_tokens=="number"?o.input_tokens:0,l=typeof o.cache_read_input_tokens=="number"?o.cache_read_input_tokens:0,h=typeof o.cache_creation_input_tokens=="number"?o.cache_creation_input_tokens:0,d=c+l+h;d>0&&d!==this.stats.contextTokensUsed&&(this.stats.contextTokensUsed=d,e=!0)}}if(t.type==="result"){let o=typeof t.total_cost_usd=="number"?t.total_cost_usd:0,c=Math.max(0,o-this.lastResultCostUsd);this.lastResultCostUsd=o,c>0&&(this.stats.costTotalUsd+=c,e=!0);let l=t.modelUsage;if(l)for(let h of Object.values(l)){let d=h;typeof d.contextWindow=="number"&&d.contextWindow!==this.stats.contextWindow&&(this.stats.contextWindow=d.contextWindow,e=!0)}this.stats.turnCount+=1,e=!0,this.recordTurnUsage(t,c)}t.type==="result"&&this.evaluateAutoCompact(),e&&this.emitStats()}recordTurnUsage(t,e){if(!this.usageRecorder)return;let s=t.usage,n=h=>typeof h=="number"?h:0,a=n(s?.input_tokens),i=n(s?.output_tokens),o=n(s?.cache_read_input_tokens),c=n(s?.cache_creation_input_tokens),l=a+i+o+c;l===0&&e===0||this.usageRecorder({ts:new Date().toISOString(),agent:this.agent.name,source:this.channelName?"channel":"chat",model:this.stats.concreteModel??this.agent.model,inputTokens:a,outputTokens:i,cacheReadTokens:o,cacheCreateTokens:c,totalTokens:l,...e>0?{costUsd:e}:{}})}evaluateAutoCompact(){if(this.isCodex)return;let t=this.agent.autoCompactThreshold??0;if(t<=0||t>=100)return;let e=this.stats.contextWindow,s=this.stats.contextTokensUsed;!e||!s||s/e*100<t||Date.now()-this.lastCompactTriggerAt<3e4||(this.needsCompactBeforeNextTurn=!0)}handleTurnEnd(){this.lastActiveAt=Date.now();let t=this.turnResponseText,e=t;if(this.agent.memory){let n=qs(t);e=At(t),n.length>0&&this.memoryWriter.capture(this.agent,n,this.captureSource(),new Date().toISOString()).catch(a=>console.warn(`Agent Fleet: chat memory capture failed for "${this.agent.name}"`,a)),this.memoryWriter.drainPending(this.agent,new Date().toISOString()).catch(a=>console.warn(`Agent Fleet: chat pending drain failed for "${this.agent.name}"`,a))}e.trim()&&this.messages.push({id:Cs(),role:"assistant",content:e,timestamp:new Date().toISOString(),toolCalls:this.turnToolCalls.length>0?[...this.turnToolCalls]:void 0});let s={text:this.turnResponseText,toolCalls:[...this.turnToolCalls]};if(this.activeOnEvent?.({type:"result",content:"",toolCalls:[...this.turnToolCalls]}),this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns--,this.isCodex){let n=this.codexQueue.shift();if(n!==void 0){this.armWatchdog(),this.startCodexTurn(n).catch(a=>{this.handleProcessError(a instanceof Error?a:new Error(String(a)))});return}this.pendingTurns=0}if(this.pendingTurns<=0){this.pendingTurns=0,this.clearWatchdog(),this.setStreaming(!1),this.persist();let n=this.turnResolve;this.turnResolve=null,this.turnReject=null,n?.(s)}}handleProcessError(t){this.isProcessAlive=!1,this.process=null,this.pendingTurns=0,this.turnResponseText="",this.turnToolCalls=[],this.codexQueue=[],this.clearWatchdog(),this.setStreaming(!1),Dt(this.settingsState),this.settingsState=null,this.codexPermState?.restore(),this.codexPermState=null,xt(this.mcpProjection),this.mcpProjection=null;let e=this.turnReject;this.turnResolve=null,this.turnReject=null,e?.(t)}handleProcessClose(){if(this.isProcessAlive=!1,this.process=null,Dt(this.settingsState),this.settingsState=null,xt(this.mcpProjection),this.mcpProjection=null,this.turnResolve){this.claudeResumeAttempted&&!this.turnResponseText.trim()&&this.clearSessionId();let t={text:this.turnResponseText,toolCalls:[...this.turnToolCalls]};this.turnResponseText.trim()&&this.messages.push({id:Cs(),role:"assistant",content:this.turnResponseText,timestamp:new Date().toISOString(),toolCalls:this.turnToolCalls.length>0?[...this.turnToolCalls]:void 0}),this.pendingTurns=0,this.turnResponseText="",this.turnToolCalls=[],this.clearWatchdog(),this.setStreaming(!1),this.persist();let e=this.turnResolve;this.turnResolve=null,this.turnReject=null,e?.(t)}}async sendMessage(t,e,s,n){this.lastActiveAt=Date.now(),this.messages.push({id:Cs(),role:"user",content:t,timestamp:new Date().toISOString(),attachments:n&&n.length>0?n:void 0});let a=s??t;if(this.basePromptSent||(a=`${await this.buildBasePrompt()}
|
|
11908
|
+
Document the reliable steps to handle this so future runs don't rediscover them.`};try{await this.repository.writeProposal(o),r.proposed=!0,await this.repository.writeCandidates(e.name,t)}catch(l){console.warn(`Agent Fleet: failed to write proposal for "${e.name}"`,l)}}}async runPendingTask({task:e,promptOverride:t}){let s=()=>{e.tags.includes("heartbeat")&&this.heartbeatsInFlight.delete(e.agent)},n=this.repository.getAgentByName(e.agent);if(!n||!n.enabled){s();return}let r=new Date().toISOString();this.runtimeState.set(n.name,{status:"running",currentTaskId:e.taskId,runStarted:r}),this.resetRunOutput(n.name),this.emitStatusChange();try{let i=await this.executor.execute(n,e,t,g=>this.emitRunOutput(n.name,g)),o=this.consumeAborted(n.name),l=o?[]:this.buildApprovals(n,i.toolsUsed),c=o?"cancelled":this.resolveRunStatus(i,l),d={runId:i.runId,agent:n.name,task:e.taskId,status:c,started:r,completed:new Date().toISOString(),durationSeconds:i.durationSeconds,tokensUsed:i.tokensUsed,costUsd:i.costUsd,model:i.resolvedModel||n.model,modelSource:i.modelSource,concreteModel:i.concreteModel,exitCode:i.exitCode,tags:Array.from(new Set([...n.tags,...e.tags])),prompt:i.prompt,output:i.outputText,toolsUsed:i.toolsUsed.map(g=>`${g.tool}${g.command?`: ${g.command}`:""}`),finalResult:i.finalResult,stderr:i.stderr,approvals:l},u=await this.repository.writeRunLog(d);await this.repository.updateTaskRunMetadata(e,{lastRun:r,runCount:e.runCount+1});let h=0;if(n.memory){let w=e.tags.includes("heartbeat")?"heartbeat":`task:${e.taskId}`,y=Tn(i.outputText);try{await this.memoryWriter.capture(n,y,w,new Date().toISOString()),h=y.length}catch(v){console.warn(`Agent Fleet: failed to append memory for "${n.name}"`,v)}}let p=e.tags.includes("heartbeat"),m=p?n.heartbeatChannel:e.channel??"",f=p?n.heartbeatChannelTarget??"":e.channelTarget??"";if(m&&!o&&d.output.trim())try{this.channelResultHandler?.(n.name,m,d.output,p?"heartbeat":e.taskId,f)}catch(g){console.warn(`Agent Fleet: channel delivery failed for ${n.name}`,g)}o&&(d.output="Task was manually stopped."),await this.refreshRunCaches(),this.runtimeState.set(n.name,{status:o||c==="success"?"idle":c==="pending_approval"?"pending":"error",currentRunId:i.runId,lastRun:{...d,filePath:u}}),o||this.notify(d,h)}catch(i){let o=this.consumeAborted(n.name),l=o?"cancelled":"failure",c=ts(e,n,this.settings),d={runId:(0,mr.randomUUID)(),agent:n.name,task:e.taskId,status:l,started:r,completed:new Date().toISOString(),durationSeconds:Math.round((Date.now()-new Date(r).getTime())/1e3),model:c.value||n.model,modelSource:c.source,exitCode:o?-1:1,tags:Array.from(new Set([...n.tags,...e.tags])),prompt:t??e.body,output:o?"Task was manually stopped.":i instanceof Error?i.message:String(i),toolsUsed:[]},u=await this.repository.writeRunLog(d);await this.refreshRunCaches(),this.runtimeState.set(n.name,{status:o?"idle":"error",lastRun:{...d,filePath:u}}),o||this.notify(d)}finally{if(s(),n.memory)try{await this.memoryWriter.drainPending(n,new Date().toISOString())}catch(i){console.warn(`Agent Fleet: failed to drain pending memory for "${n.name}"`,i)}this.clearRunOutput(n.name),this.emitStatusChange()}}buildApprovals(e,t){let s=t.filter(n=>e.approvalRequired.includes(n.tool)).map(n=>({tool:n.tool,command:n.command,reason:n.reason,status:"pending"}));return s.length>0?s:void 0}resolveRunStatus(e,t){return t?.length?"pending_approval":e.timedOut?"timeout":e.exitCode===0?"success":"failure"}notify(e,t=0){if(this.settings.notificationLevel==="none"||this.settings.notificationLevel==="failures-only"&&e.status==="success")return;let n=(re(e.output).map(o=>o.trim()).find(o=>o&&!o.startsWith("{")&&!o.startsWith("["))??"").slice(0,120)||e.status,r=t>0?` \xB7 captured ${t} memory fact${t===1?"":"s"}`:"",i=e.status==="success"?`\u2705 ${e.agent}: ${n}${r}`:e.status==="pending_approval"?`\u{1F535} ${e.agent} needs approval: ${(e.approvals??[])[0]?.tool??"tool action"}`:`\u274C ${e.agent}: ${n}`;new xo.Notice(i,e.status==="success"?5e3:0)}emitStatusChange(){for(let e of this.statusChangeListeners)e()}};function zd(a){return a.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-{2,}/g,"-").replace(/^-|-$/g,"")}function Ks(a,e){return`${a}-${zd(e)}`}var gs="af-channel-cred",Js="af-mcp-secret",Zn=class{constructor(e){this.storage=e;e||console.warn("Agent Fleet: SecretStorage unavailable (Obsidian < 1.11.4). Secrets will use plaintext fallback.")}get available(){return!!this.storage}setJson(e,t,s){if(!this.storage)return;let n=Ks(e,t);this.storage.setSecret(n,JSON.stringify(s))}getJson(e,t){if(!this.storage)return null;let s=Ks(e,t),n=this.storage.getSecret(s);if(!n)return null;try{return JSON.parse(n)}catch{return null}}setString(e,t,s){if(!this.storage)return;let n=Ks(e,t);this.storage.setSecret(n,s)}getString(e,t){if(!this.storage)return null;let s=Ks(e,t);return this.storage.getSecret(s)||null}delete(e,t){if(!this.storage)return;let s=Ks(e,t);this.storage.setSecret(s,"")}listByPrefix(e){return this.storage?this.storage.listSecrets().filter(t=>t.startsWith(e+"-")):[]}};var ea=class{tokens=new Map;oauthTokens=new Map;secretStore;setSecretStore(e){this.secretStore=e}storeProbeToken(e,t){this.tokens.set(e,t)}storeStaticToken(e,t){this.tokens.set(e,t),this.secretStore?.setJson(Js,e,{accessToken:t})}storeOAuthToken(e,t){this.oauthTokens.set(e,t),this.tokens.set(e,t.accessToken),this.secretStore?.setJson(Js,e,{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresAt:t.expiresAt,tokenEndpoint:t.tokenEndpoint,clientId:t.clientId,resource:t.resource})}hydrate(e){if(!this.secretStore)return null;let t=this.secretStore.getJson(Js,e);return t?.accessToken?(this.tokens.set(e,t.accessToken),t.tokenEndpoint&&t.clientId&&t.resource&&this.oauthTokens.set(e,{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresAt:t.expiresAt,tokenEndpoint:t.tokenEndpoint,clientId:t.clientId,resource:t.resource}),t):null}getToken(e){return this.tokens.get(e)??this.hydrate(e)?.accessToken??void 0}getOAuthToken(e){return this.oauthTokens.has(e)?this.oauthTokens.get(e):(this.hydrate(e),this.oauthTokens.get(e))}hasToken(e){return this.tokens.has(e)||!!this.hydrate(e)}removeToken(e){this.tokens.delete(e),this.oauthTokens.delete(e),this.secretStore?.delete(Js,e)}getExpiringTokens(e=5*6e4){let t=new Map,s=Date.now();for(let[n,r]of this.oauthTokens)r.refreshToken&&r.expiresAt&&r.expiresAt-s<e&&t.set(n,r);return t}};var xt=require("obsidian");var ta=require("crypto"),gt=require("obsidian");function Xs(){return(0,ta.randomUUID)()}function So(a){let e=`${a.timestamp}|${a.content.slice(0,80)}`;return(0,ta.createHash)("sha1").update(e).digest("hex").slice(0,16)}var ys=class a{constructor(e,t,s,n,r){this.agent=e;this.settings=t;this.repository=s;this.vault=n,this.channelName=r?.channelName,this.conversationId=r?.conversationId,this.channelContext=r?.channelContext,this.inAppConversationId=r?.inAppConversationId,this.threadAnchorId=r?.threadAnchorId,this.parentSession=r?.parentSession,this.mcpAuth=r?.mcpAuth,this.memoryWriter=new fs(s)}messages=[];isStreaming=!1;isProcessAlive=!1;settingsState=null;mcpProjection=null;get pendingTurnCount(){return this.pendingTurns}lastActiveAt=Date.now();process=null;claudeSessionId=null;claudeResumeAttempted=!1;vault;stdoutBuffer="";static STDOUT_LINE_CAP=10*1024*1024;processListeners=null;basePromptSent=!1;codexTurnState=null;codexQueue=[];codexResumeAttempted=!1;codexTurnErrors=[];codexStderr="";codexPermState=null;get isCodex(){return Bt(this.agent.adapter)==="codex"}channelName;conversationId;channelContext;inAppConversationId;conversationName="";threadAnchorId;parentSession;threadAnchorIndex;threads=new Map;threadIndex={};activeOnEvent=null;turnResponseText="";displayedLen=0;turnToolCalls=[];pendingTurns=0;turnResolve=null;turnReject=null;needsCompactBeforeNextTurn=!1;lastCompactTriggerAt=0;static WATCHDOG_FALLBACK_MINUTES=10;watchdogTimer=null;getWatchdogMs(){let e=this.settings.chatWatchdogMinutes;return(typeof e=="number"&&e>0?e:a.WATCHDOG_FALLBACK_MINUTES)*60*1e3}armWatchdog(){this.clearWatchdog();let e=this.getWatchdogMs();this.watchdogTimer=window.setTimeout(()=>{if(this.watchdogTimer=null,!this.isStreaming)return;this.activeOnEvent?.({type:"error",content:"",errorMessage:`no response from the CLI for ${Math.round(e/6e4)} minutes \u2014 giving up`});let t=new Error("Watchdog timeout");this.handleProcessError(t);try{this.process?.kill()}catch{}},e)}clearWatchdog(){this.watchdogTimer&&(window.clearTimeout(this.watchdogTimer),this.watchdogTimer=null)}currentToolName;activityListeners=new Set;onActivityChange(e){return this.activityListeners.add(e),e(),()=>{this.activityListeners.delete(e)}}emitActivity(){for(let e of this.activityListeners)e()}setStreaming(e){this.isStreaming!==e&&(this.isStreaming=e,e||(this.currentToolName=void 0),this.emitActivity())}setCurrentTool(e){this.currentToolName!==e&&(this.currentToolName=e,this.emitActivity())}stats={costTotalUsd:0,turnCount:0};usageRecorder;lastResultCostUsd=0;setUsageRecorder(e){this.usageRecorder=e}statsListeners=new Set;onStatsChange(e){return this.statsListeners.add(e),e({...this.stats}),()=>{this.statsListeners.delete(e)}}getStats(){return{...this.stats}}emitStats(){let e={...this.stats};for(let t of this.statsListeners)t(e)}mcpAuth;buildMcpProjection(e){let t=this.agent.memory?this.repository.getPendingDirAbsolutePath(this.agent.name):null,s=Vn({registry:this.repository.getMcpServers(),agentGrants:this.agent.mcpServers??[],getBearerToken:n=>this.mcpAuth?.getToken(n),remember:t?{pendingDir:t,source:`mcp:${this.captureSource()}`}:null});return this.mcpProjection=Yn(e,this.agent.adapter,s),{args:this.mcpProjection?.args??[],env:this.mcpProjection?.env??{},allowServers:s.map(n=>n.def.name)}}memoryWriter;captureSource(){return`chat:${this.inAppConversationId||this.conversationId||"default"}`}getConversationName(){return this.conversationName}async setConversationName(e){this.conversationName=e,await this.persist()}refreshAgent(){let e=this.repository.getAgentByName(this.agent.name);e&&(this.agent=e)}get isThread(){return!!this.threadAnchorId}async loadPersistedState(){let e=this.getChatFilePath(),t=this.vault.getAbstractFileByPath(e);if(!(t instanceof gt.TFile))return!1;try{let s=await this.vault.cachedRead(t);if(this.isThread){let r=JSON.parse(s);return r.messages?.length>0||r.sessionId?(this.messages=(r.messages??[]).map(i=>i.id?i:{...i,id:So(i)}),this.claudeSessionId=r.sessionId??null,this.threadAnchorIndex=r.anchorIndex,this.claudeSessionId&&(this.basePromptSent=!0),!0):!1}let n=JSON.parse(s);if(n.name&&(this.conversationName=n.name),n.messages?.length>0)return this.messages=n.messages.map(r=>r.id?r:{...r,id:So(r)}),this.claudeSessionId=n.sessionId??null,this.threadIndex=n.threads??{},this.claudeSessionId&&(this.basePromptSent=!0),!0}catch{}return!1}getThreadIndex(){return{...this.threadIndex}}async persist(){let e=new Date().toISOString(),t=this.getChatFilePath(),s;if(this.isThread){let r={anchorMessageId:this.threadAnchorId,anchorIndex:this.threadAnchorIndex??0,sessionId:this.claudeSessionId,messages:this.messages,createdAt:this.parentSession?.threadIndex[this.threadAnchorId]?.createdAt??e,lastActive:e};s=JSON.stringify(r,null,2)}else{let r={sessionId:this.claudeSessionId,messages:this.messages,lastActive:e,name:this.conversationName||void 0,threads:Object.keys(this.threadIndex).length>0?this.threadIndex:void 0};s=JSON.stringify(r,null,2)}let n=this.vault.getAbstractFileByPath(t);n instanceof gt.TFile?await this.vault.modify(n,s):(await this.ensureParentFolders(t),await this.vault.create(t,s)),this.isThread&&this.parentSession&&this.threadAnchorId&&await this.parentSession.upsertThreadIndex(this.threadAnchorId,{path:t,createdAt:this.parentSession.threadIndex[this.threadAnchorId]?.createdAt??e,messageCount:this.messages.length,lastActive:e})}async upsertThreadIndex(e,t){this.threadIndex[e]=t,await this.persist()}async ensureParentFolders(e){let t=e.lastIndexOf("/");if(t<=0)return;let n=e.slice(0,t).split("/"),r="";for(let i of n)if(r=r?`${r}/${i}`:i,!this.vault.getAbstractFileByPath(r))try{await this.vault.createFolder(r)}catch(o){if(!(o instanceof Error?o.message:String(o)).includes("already exists"))throw o}}async clearPersistedState(){let e=this.getChatFilePath();await this.repository.trashFile(e),this.messages=[],this.claudeSessionId=null,this.basePromptSent=!1}getChatFilePath(){if(this.threadAnchorId&&this.parentSession)return this.parentSession.getThreadFilePath(this.threadAnchorId);if(this.channelName&&this.conversationId){let s=this.settings.fleetFolder,n=z(this.conversationId)||"conversation";return(0,gt.normalizePath)(`${s}/channels/${this.channelName}/sessions/${n}.json`)}if(!this.inAppConversationId)throw new Error("ChatSession requires inAppConversationId (or channel options) to resolve a file path");let e=z(this.inAppConversationId)||"conversation";if(this.agent.isFolder){let s=this.agent.filePath.replace(/\/agent\.md$/,"");return(0,gt.normalizePath)(`${s}/conversations/${e}.json`)}let t=this.repository.getMemoryPath(this.agent.name).replace(/\/[^/]+$/,"");return(0,gt.normalizePath)(`${t}/${this.agent.name}-conversations/${e}.json`)}getThreadFilePath(e){let t=this.getParentChatFilePath(),s=t.replace(/\/[^/]+$/,""),n=t.slice(s.length+1).replace(/\.json$/,"");return(0,gt.normalizePath)(`${s}/${n}.threads/${e}.json`)}getParentChatFilePath(){if(this.channelName&&this.conversationId){let e=this.settings.fleetFolder,t=z(this.conversationId)||"conversation";return(0,gt.normalizePath)(`${e}/channels/${this.channelName}/sessions/${t}.json`)}if(this.inAppConversationId){let e=z(this.inAppConversationId)||"conversation";if(this.agent.isFolder){let s=this.agent.filePath.replace(/\/agent\.md$/,"");return(0,gt.normalizePath)(`${s}/conversations/${e}.json`)}let t=this.repository.getMemoryPath(this.agent.name).replace(/\/[^/]+$/,"");return(0,gt.normalizePath)(`${t}/${this.agent.name}-conversations/${e}.json`)}throw new Error("ChatSession requires inAppConversationId (or channel options) to resolve a parent file path")}async ensureProcess(){if(this.process&&this.isProcessAlive)return;this.refreshAgent();let e=["--input-format","stream-json","--output-format","stream-json","--verbose"];this.claudeSessionId?(e.push("--resume",this.claudeSessionId),this.basePromptSent=!0,this.claudeResumeAttempted=!0):this.claudeResumeAttempted=!1;let t=ts(null,this.agent,this.settings);Gs(t.value)&&e.push("--model",t.value);let s=this.agent.permissionMode?.trim();s&&s!=="default"?e.push("--permission-mode",s):e.push("--permission-mode","bypassPermissions"),this.agent.effort&&e.push("--effort",this.agent.effort);let n=this.agent.cwd?.trim()?this.agent.cwd:this.repository.getVaultBasePath()??".",r=this.buildMcpProjection(n);e.push(...r.args),this.settingsState=jn(n,this.agent,{mcpAllowServers:r.allowServers});let i=wt(this.settings.claudeCliPath,e,{cwd:n,env:{...process.env,AWS_REGION:this.settings.awsRegion,...r.env}});this.process=i,this.isProcessAlive=!0,this.stdoutBuffer="",this.lastResultCostUsd=0,this.processListeners={onStdout:o=>this.handleStdout(o),onStderr:()=>{},onError:o=>this.handleProcessError(o),onClose:()=>this.handleProcessClose()},i.stdout.on("data",this.processListeners.onStdout),i.stderr.on("data",this.processListeners.onStderr),i.on("error",this.processListeners.onError),i.on("close",this.processListeners.onClose)}detachProcessListeners(){this.process&&this.processListeners&&(this.process.stdout?.removeListener("data",this.processListeners.onStdout),this.process.stderr?.removeListener("data",this.processListeners.onStderr),this.process.removeListener("error",this.processListeners.onError),this.process.removeListener("close",this.processListeners.onClose)),this.processListeners=null}handleStdout(e){this.isStreaming&&this.armWatchdog(),this.stdoutBuffer+=e.toString();let t=re(this.stdoutBuffer);this.stdoutBuffer=t.pop()??"",this.stdoutBuffer.length>a.STDOUT_LINE_CAP&&(console.warn(`Agent Fleet: chat stdout line exceeded ${a.STDOUT_LINE_CAP} chars \u2014 dropping partial line`),this.stdoutBuffer="");for(let s of t){let n=s.trim();if(n)try{let r=JSON.parse(n);this.handleEvent(r)}catch{}}}handleEvent(e){if(this.isCodex){this.handleCodexEvent(e);return}if(typeof e.session_id=="string"&&(this.claudeSessionId=e.session_id),this.updateStatsFromEvent(e),e.type==="system"&&e.subtype==="compact_boundary"){let s=e.compact_metadata,n=s&&typeof s.pre_tokens=="number"?s.pre_tokens:0,r=s&&typeof s.post_tokens=="number"?s.post_tokens:0;r>0&&(this.stats.contextTokensUsed=r),this.stats.lastCompact={preTokens:n,postTokens:r},this.emitStats(),this.needsCompactBeforeNextTurn=!1,this.activeOnEvent?.({type:"compacted",content:"",compact:{preTokens:n,postTokens:r}});return}if(e.type==="result"){let s=typeof e.api_error_status=="string"&&!!e.api_error_status;if(e.is_error===!0||s){let n=this.describeResultError(e);this.activeOnEvent?.({type:"error",content:"",errorMessage:n}),this.claudeResumeAttempted&&e.is_error===!0&&!s&&this.clearSessionId()}this.handleTurnEnd();return}let t=this.parseStreamEvent(e);t&&this.dispatchStreamEvent(t)}dispatchStreamEvent(e){let t=e;if(e.type==="text"){let s=this.turnResponseText.length===0;if(s&&(this.displayedLen=0),this.turnResponseText+=e.content,this.setCurrentTool(void 0),s&&this.turnResponseText.length>0&&this.emitActivity(),this.agent.memory){let n=hi(this.turnResponseText),r=n.length>this.displayedLen?n.slice(this.displayedLen):"";this.displayedLen=n.length,t={...e,content:r}}}else e.type==="tool_use"&&e.toolName&&(this.turnToolCalls.push({name:e.toolName,command:e.content||void 0}),this.setCurrentTool(e.toolName));this.activeOnEvent?.(t)}handleCodexEvent(e){this.codexTurnState||(this.codexTurnState=lr());let t=no(e,this.codexTurnState);for(let s of t)switch(s.kind){case"session":this.claudeSessionId=s.sessionId;break;case"text":this.dispatchStreamEvent({type:"text",content:s.text});break;case"tool":this.dispatchStreamEvent({type:"tool_use",content:s.command?s.command.slice(0,150):"",toolName:s.toolName});break;case"usage":{s.contextTokens>0&&s.contextTokens!==this.stats.contextTokensUsed&&(this.stats.contextTokensUsed=s.contextTokens),this.stats.turnCount+=1,this.emitStats();break}case"turn-failed":case"error":this.codexTurnErrors.push(s.message),this.activeOnEvent?.({type:"error",content:"",errorMessage:s.message});break}}get hasCurrentTurnText(){return this.turnResponseText.length>0}describeResultError(e){let t=[],s=typeof e.api_error_status=="string"?e.api_error_status:"",n=typeof e.subtype=="string"?e.subtype:"",r=typeof e.result=="string"?e.result:"";return s?t.push(`API ${s}`):n?t.push(n.replace(/_/g," ")):t.push("unknown error"),r&&t.push(`\u2014 ${r}`),t.join(" ")}updateStatsFromEvent(e){let t=!1,s=typeof e.model=="string"?e.model:void 0,n=e.message,r=n&&typeof n.model=="string"?n.model:void 0,i=s||r;if(i&&i!==this.stats.concreteModel&&(this.stats.concreteModel=i,t=!0),e.type==="rate_limit_event"){let o=e.rate_limit_info;o&&(this.stats.rateLimit={type:typeof o.rateLimitType=="string"?o.rateLimitType:"unknown",resetsAt:typeof o.resetsAt=="number"?o.resetsAt:void 0,status:typeof o.status=="string"?o.status:void 0,isUsingOverage:typeof o.isUsingOverage=="boolean"?o.isUsingOverage:void 0},t=!0)}if(e.type==="assistant"&&n){let o=n.usage;if(o){let l=typeof o.input_tokens=="number"?o.input_tokens:0,c=typeof o.cache_read_input_tokens=="number"?o.cache_read_input_tokens:0,d=typeof o.cache_creation_input_tokens=="number"?o.cache_creation_input_tokens:0,u=l+c+d;u>0&&u!==this.stats.contextTokensUsed&&(this.stats.contextTokensUsed=u,t=!0)}}if(e.type==="result"){let o=typeof e.total_cost_usd=="number"?e.total_cost_usd:0,l=Math.max(0,o-this.lastResultCostUsd);this.lastResultCostUsd=o,l>0&&(this.stats.costTotalUsd+=l,t=!0);let c=e.modelUsage;if(c)for(let d of Object.values(c)){let u=d;typeof u.contextWindow=="number"&&u.contextWindow!==this.stats.contextWindow&&(this.stats.contextWindow=u.contextWindow,t=!0)}this.stats.turnCount+=1,t=!0,this.recordTurnUsage(e,l)}e.type==="result"&&this.evaluateAutoCompact(),t&&this.emitStats()}recordTurnUsage(e,t){if(!this.usageRecorder)return;let s=e.usage,n=d=>typeof d=="number"?d:0,r=n(s?.input_tokens),i=n(s?.output_tokens),o=n(s?.cache_read_input_tokens),l=n(s?.cache_creation_input_tokens),c=r+i+o+l;c===0&&t===0||this.usageRecorder({ts:new Date().toISOString(),agent:this.agent.name,source:this.channelName?"channel":"chat",model:this.stats.concreteModel??this.agent.model,inputTokens:r,outputTokens:i,cacheReadTokens:o,cacheCreateTokens:l,totalTokens:c,...t>0?{costUsd:t}:{}})}evaluateAutoCompact(){if(this.isCodex)return;let e=this.agent.autoCompactThreshold??0;if(e<=0||e>=100)return;let t=this.stats.contextWindow,s=this.stats.contextTokensUsed;!t||!s||s/t*100<e||Date.now()-this.lastCompactTriggerAt<3e4||(this.needsCompactBeforeNextTurn=!0)}handleTurnEnd(){this.lastActiveAt=Date.now();let e=this.turnResponseText,t=e;if(this.agent.memory){let n=Tn(e);t=Jt(e),n.length>0&&this.memoryWriter.capture(this.agent,n,this.captureSource(),new Date().toISOString()).catch(r=>console.warn(`Agent Fleet: chat memory capture failed for "${this.agent.name}"`,r)),this.memoryWriter.drainPending(this.agent,new Date().toISOString()).catch(r=>console.warn(`Agent Fleet: chat pending drain failed for "${this.agent.name}"`,r))}t.trim()&&this.messages.push({id:Xs(),role:"assistant",content:t,timestamp:new Date().toISOString(),toolCalls:this.turnToolCalls.length>0?[...this.turnToolCalls]:void 0});let s={text:this.turnResponseText,toolCalls:[...this.turnToolCalls]};if(this.activeOnEvent?.({type:"result",content:"",toolCalls:[...this.turnToolCalls]}),this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns--,this.isCodex){let n=this.codexQueue.shift();if(n!==void 0){this.armWatchdog(),this.startCodexTurn(n).catch(r=>{let i=1+this.codexQueue.length;this.activeOnEvent?.({type:"error",content:"",errorMessage:`failed to start queued Codex turn \u2014 dropping ${i} queued message${i===1?"":"s"}: ${r instanceof Error?r.message:String(r)}`}),this.handleProcessError(r instanceof Error?r:new Error(String(r)))});return}this.pendingTurns=0}if(this.pendingTurns<=0){this.pendingTurns=0,this.clearWatchdog(),this.setStreaming(!1),this.persist();let n=this.turnResolve;this.turnResolve=null,this.turnReject=null,n?.(s)}}handleProcessError(e){this.isProcessAlive=!1,this.process=null,this.pendingTurns=0,this.turnResponseText="",this.turnToolCalls=[],this.codexQueue=[],this.clearWatchdog(),this.setStreaming(!1),Zt(this.settingsState),this.settingsState=null,this.codexPermState?.restore(),this.codexPermState=null,Ut(this.mcpProjection),this.mcpProjection=null;let t=this.turnReject;this.turnResolve=null,this.turnReject=null,t?.(e)}handleProcessClose(){this.isProcessAlive=!1,this.process=null,Zt(this.settingsState),this.settingsState=null,Ut(this.mcpProjection),this.mcpProjection=null;let e=this.turnResolve,t=null;e&&(this.claudeResumeAttempted&&!this.turnResponseText.trim()&&this.clearSessionId(),t={text:this.turnResponseText,toolCalls:[...this.turnToolCalls]},this.turnResponseText.trim()&&this.messages.push({id:Xs(),role:"assistant",content:this.turnResponseText,timestamp:new Date().toISOString(),toolCalls:this.turnToolCalls.length>0?[...this.turnToolCalls]:void 0})),this.pendingTurns=0,this.turnResponseText="",this.turnToolCalls=[],this.clearWatchdog(),this.setStreaming(!1),e&&t&&(this.persist(),this.turnResolve=null,this.turnReject=null,e(t))}async sendMessage(e,t,s,n){this.lastActiveAt=Date.now(),this.messages.push({id:Xs(),role:"user",content:e,timestamp:new Date().toISOString(),attachments:n&&n.length>0?n:void 0});let r=s??e;if(this.basePromptSent||(r=`${await this.buildBasePrompt()}
|
|
11907
11909
|
|
|
11908
11910
|
## Task
|
|
11909
|
-
${
|
|
11910
|
-
`)};try{i&&o("/compact"),o(
|
|
11911
|
-
`)}catch(i){console.warn("Agent Fleet: injectMessage stdin write failed",i);return}this.pendingTurns++}abort(){this.detachProcessListeners(),this.process&&(this.process.kill(),this.process=null),this.isProcessAlive=!1,this.stdoutBuffer="",this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns=0,this.codexQueue=[],this.clearWatchdog(),this.setStreaming(!1),
|
|
11912
|
-
${
|
|
11913
|
-
${n.referencesBody.trim()}`),n.examplesBody.trim()&&a.push(`### Examples
|
|
11914
|
-
${n.examplesBody.trim()}`),t.push(`## Skill: ${n.name}
|
|
11915
|
-
${a.join(`
|
|
11916
|
-
|
|
11917
|
-
`)}`)}}if(this.agent.skillsBody.trim()&&t.push(`## Agent Skills
|
|
11918
|
-
${this.agent.skillsBody.trim()}`),this.agent.contextBody.trim()&&t.push(`## Agent Context
|
|
11919
|
-
${this.agent.contextBody.trim()}`),this.agent.memory){let s=await this.repository.readWorkingMemory(this.agent.name),n=Gs(this.agent,s);n&&t.push(n)}this.channelContext&&this.channelContext.trim()&&t.push(`## Channel Context
|
|
11920
|
-
${this.channelContext.trim()}`);let e=rn(this.agent,this.repository);if(e&&t.push(e),this.isThread&&this.parentSession&&this.threadAnchorIndex!==void 0){let s="You are continuing a side thread from this conversation. The user is following up on one of your earlier replies and wants to explore something specific without adding to the main thread. Your answers here stay in this thread only and will NOT be added back to the main conversation.",n=this.parentSession.messages.slice(0,this.threadAnchorIndex+1),a=["## Conversation so far"];for(let i of n){let o=i.role==="user"?"User":"Assistant";a.push(`${o}: ${i.content.trim()}`)}t.push(`## Thread Mode
|
|
11921
|
-
${s}
|
|
11911
|
+
${r}`,this.basePromptSent=!0),this.isCodex){this.stats.lastCompact&&(this.stats.lastCompact=void 0,this.emitStats()),this.activeOnEvent=t,this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns=1,this.setStreaming(!0),this.armWatchdog();try{await this.startCodexTurn(r)}catch(l){throw this.pendingTurns=0,this.clearWatchdog(),this.setStreaming(!1),new Error(`Failed to start Codex process: ${l instanceof Error?l.message:String(l)}`)}return new Promise((l,c)=>{this.turnResolve=l,this.turnReject=c})}await this.ensureProcess();let i=this.needsCompactBeforeNextTurn;i&&(this.needsCompactBeforeNextTurn=!1,this.lastCompactTriggerAt=Date.now()),this.stats.lastCompact&&(this.stats.lastCompact=void 0,this.emitStats()),this.activeOnEvent=t,this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns=i?2:1,this.setStreaming(!0),this.armWatchdog();let o=l=>{let c=JSON.stringify({type:"user",message:{role:"user",content:l}});this.process.stdin.write(c+`
|
|
11912
|
+
`)};try{i&&o("/compact"),o(r)}catch(l){throw this.pendingTurns=0,this.setStreaming(!1),new Error(`Failed to write to Claude process stdin: ${l instanceof Error?l.message:String(l)}`)}return new Promise((l,c)=>{this.turnResolve=l,this.turnReject=c})}scheduleCompact(){this.isCodex||(this.needsCompactBeforeNextTurn=!0)}async startCodexTurn(e){this.refreshAgent();let t=ts(null,this.agent,this.settings),s=await zs.buildExec({prompt:e,model:Gs(t.value)?t.value:"",modelSource:t.source,effort:this.agent.effort??"",agent:this.agent,settings:this.settings,streaming:!0,resumeSessionId:this.claudeSessionId});t.value&&this.stats.concreteModel!==t.value&&(this.stats.concreteModel=t.value,this.emitStats()),this.codexTurnState=lr(),this.codexResumeAttempted=!!this.claudeSessionId,this.codexTurnErrors=[],this.codexStderr="";let n=this.agent.cwd?.trim()?this.agent.cwd:this.repository.getVaultBasePath()??".",r=this.buildMcpProjection(n);s.args.push(...r.args),this.codexPermState=await zs.setupPermissions(n,this.agent,this.settings);let i=wt(s.cliPath,s.args,{cwd:n,env:{...process.env,AWS_REGION:this.settings.awsRegion,...r.env,...this.codexPermState?.env??{}}});this.process=i,this.isProcessAlive=!0,this.stdoutBuffer="",this.processListeners={onStdout:o=>this.handleStdout(o),onStderr:o=>{this.codexStderr+=o.toString()},onError:o=>this.handleProcessError(o),onClose:o=>this.handleCodexProcessClose(o)},i.stdout.on("data",this.processListeners.onStdout),i.stderr.on("data",this.processListeners.onStderr),i.on("error",this.processListeners.onError),i.on("close",this.processListeners.onClose);try{i.stdin.write(s.stdinPayload??e),i.stdin.end()}catch(o){this.detachProcessListeners();try{i.kill()}catch{}throw this.process=null,this.isProcessAlive=!1,o instanceof Error?o:new Error(String(o))}}handleCodexProcessClose(e){if(this.detachProcessListeners(),this.isProcessAlive=!1,this.process=null,this.stdoutBuffer="",this.codexPermState?.restore(),this.codexPermState=null,Ut(this.mcpProjection),this.mcpProjection=null,e!==0&&!this.turnResponseText.trim()){let s=this.codexTurnErrors.join("; ")||this.codexStderr.trim().slice(-500)||`Codex CLI exited with code ${e??"unknown"}`;this.codexResumeAttempted&&this.clearSessionId(),this.codexQueue=[],this.activeOnEvent?.({type:"error",content:"",errorMessage:s})}this.handleTurnEnd()}injectMessage(e,t,s){if(this.isCodex){if(!this.isStreaming&&this.pendingTurns===0)return;this.messages.push({id:Xs(),role:"user",content:e,timestamp:new Date().toISOString(),attachments:s&&s.length>0?s:void 0}),this.codexQueue.push(t??e),this.pendingTurns++;return}if(!this.process||!this.isProcessAlive)return;this.messages.push({id:Xs(),role:"user",content:e,timestamp:new Date().toISOString(),attachments:s&&s.length>0?s:void 0});let r=JSON.stringify({type:"user",message:{role:"user",content:t??e}});try{this.process.stdin.write(r+`
|
|
11913
|
+
`)}catch(i){console.warn("Agent Fleet: injectMessage stdin write failed",i);return}this.pendingTurns++}abort(){this.detachProcessListeners(),this.process&&(this.process.kill(),this.process=null),this.isProcessAlive=!1,this.stdoutBuffer="",this.turnResponseText="",this.turnToolCalls=[],this.pendingTurns=0,this.codexQueue=[],this.clearWatchdog(),this.setStreaming(!1),Zt(this.settingsState),this.settingsState=null,this.codexPermState?.restore(),this.codexPermState=null,Ut(this.mcpProjection),this.mcpProjection=null;let e=this.turnReject;this.turnResolve=null,this.turnReject=null,e?.(new Error("Aborted"))}dispose(){for(let e of this.threads.values())e.abort();this.threads.clear(),this.threadIndex={},this.abort()}hibernate(){this.isStreaming||this.pendingTurns>0||(this.detachProcessListeners(),this.process&&(this.process.kill(),this.process=null),this.isProcessAlive=!1,this.stdoutBuffer="",Zt(this.settingsState),this.settingsState=null,Ut(this.mcpProjection),this.mcpProjection=null)}clearSessionId(){this.claudeSessionId=null,this.basePromptSent=!1,this.claudeResumeAttempted=!1}async buildBasePrompt(){let e=await qn(this.repository,this.agent,{memoryActive:this.agent.memory,channelContext:this.channelContext});if(this.isThread&&this.parentSession&&this.threadAnchorIndex!==void 0){let t="You are continuing a side thread from this conversation. The user is following up on one of your earlier replies and wants to explore something specific without adding to the main thread. Your answers here stay in this thread only and will NOT be added back to the main conversation.",s=this.parentSession.messages.slice(0,this.threadAnchorIndex+1),n=["## Conversation so far"];for(let r of s){let i=r.role==="user"?"User":"Assistant";n.push(`${i}: ${r.content.trim()}`)}e.push(`## Thread Mode
|
|
11914
|
+
${t}
|
|
11922
11915
|
|
|
11923
|
-
${
|
|
11924
|
-
`)}`)}return
|
|
11916
|
+
${n.join(`
|
|
11917
|
+
`)}`)}return e.filter(Boolean).join(`
|
|
11918
|
+
|
|
11919
|
+
`)}async openOrCreateThread(e){if(this.isThread)throw new Error("Nested threads are not supported.");let t=this.threads.get(e);if(t)return t;let s=this.messages.findIndex(i=>i.id===e);if(s<0)throw new Error(`Thread anchor message "${e}" not found in parent.`);let n=new a(this.agent,this.settings,this.repository,this.vault,{threadAnchorId:e,parentSession:this,mcpAuth:this.mcpAuth});return n.threadAnchorIndex=s,await n.loadPersistedState()||(n.threadAnchorIndex=s),this.threads.set(e,n),n}closeThread(e){let t=this.threads.get(e);t&&(t.abort(),this.threads.delete(e))}hibernateIdleThreads(e){let t=Date.now();for(let s of this.threads.values())s.isProcessAlive&&t-s.lastActiveAt>e&&s.hibernate()}parseStreamEvent(e){let t=e.type;if(t==="assistant"){let s=e.message;if(s?.content&&Array.isArray(s.content))for(let n of s.content){if(n.type==="text"&&typeof n.text=="string")return{type:"text",content:n.text};if(n.type==="tool_use"){let r=String(n.name??"tool"),i=n.input,o=i?.command??i?.content??i?.file_path??i?.path??"";return{type:"tool_use",content:o?String(o).slice(0,150):"",toolName:r}}}}if(t==="content_block_delta"){let s=e.delta;if(s?.type==="text_delta"&&typeof s.text=="string")return{type:"text",content:s.text}}return null}};var sa=class{constructor(e){this.config=e;this.now=e.now??Date.now}buckets=new Map;now;tryConsume(e){let t=this.now(),s=t-this.config.windowMs,r=(this.buckets.get(e)??[]).filter(i=>i>s);return r.length>=this.config.maxPerWindow?(this.buckets.set(e,r),!1):(r.push(t),this.buckets.set(e,r),!0)}currentCount(e){let s=this.now()-this.config.windowMs;return(this.buckets.get(e)??[]).filter(r=>r>s).length}reset(e){this.buckets.delete(e)}resetAll(){this.buckets.clear()}};function Qs(a){let e=Gd(a),t=[];for(let s of e)if(s.kind==="code"){let n=s.text.replace(/^```[^\n]*\n/,"```\n");t.push(n)}else t.push(Vd(s.text));return t.join("")}function Gd(a){let e=[],t=0,s=!1,n=0;for(;t<a.length;)a.startsWith("```",t)?s?(t+=3,a[t]===`
|
|
11920
|
+
`&&(t+=1),e.push({kind:"code",text:a.slice(n,t)}),n=t,s=!1):(t>n&&e.push({kind:"prose",text:a.slice(n,t)}),n=t,s=!0,t+=3):t+=1;return n<a.length&&e.push({kind:s?"code":"prose",text:a.slice(n)}),e}function Vd(a){return Yd(a).map(s=>{if(s.isCode)return s.text;let n=s.text;return n=n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),n=n.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(r,i,o)=>`<${o}|${i}>`),n=n.replace(/\*\*([^*]+)\*\*/g,"*$1*"),n=n.replace(/^#{1,6}\s+(.+)$/gm,"*$1*"),n}).join("")}function Yd(a){let e=[],t=/`([^`\n]+)`/g,s=0,n;for(;n=t.exec(a);)n.index>s&&e.push({text:a.slice(s,n.index),isCode:!1}),e.push({text:n[0],isCode:!0}),s=n.index+n[0].length;return s<a.length&&e.push({text:a.slice(s),isCode:!1}),e}function Co(a,e=3e3){if(a.length<=e)return[a];let t=[],s=a;for(;s.length>e;){let n=s.slice(0,e),r=Kd(n)%2===1,i;if(r){let o=Jd(n);if(o>0)i=o;else{t.push(n+"\n```"),s="```\n"+s.slice(e);continue}}else{if(i=n.lastIndexOf(`
|
|
11925
11921
|
|
|
11926
|
-
`)
|
|
11927
|
-
|
|
11922
|
+
`),i<e/2){let o=n.lastIndexOf(`
|
|
11923
|
+
`);o>e/2?i=o:i=e}i<=0&&(i=e)}t.push(s.slice(0,i)),s=s.slice(i).replace(/^\n+/,"")}return s.length>0&&t.push(s),t}function ss(a,e){if(a.length<=e)return[a];let t=[],s=a;for(;s.length>e;){let n=s.lastIndexOf(`
|
|
11928
11924
|
|
|
11929
|
-
|
|
11930
|
-
|
|
11925
|
+
`,e);n<e/2&&(n=s.lastIndexOf(`
|
|
11926
|
+
`,e)),n<e/2&&(n=e),t.push(s.slice(0,n)),s=s.slice(n).replace(/^\n+/,"")}return s&&t.push(s),t}function Kd(a){let e=0,t=0;for(;(t=a.indexOf("```",t))!==-1;)e+=1,t+=3;return e}function Jd(a){let e=0,t=0,s=0;for(;s<a.length;){let n=a.indexOf("```",s);if(n===-1)break;e+=1,s=n+3,e%2===0&&(t=s)}return t}function Xd(a,e){let t=a.trim(),s=t.toLowerCase();for(let n of e){let r=n.toLowerCase(),i=[`use ${r}:`,`use ${r}`,`@${r}:`,`@${r}`,`${r}:`];for(let o of i)if(s.startsWith(o)){let l=t.slice(o.length).trim();return{agent:n,rest:l}}}return null}var na=class{constructor(e){this.deps=e;this.now=e.now??(()=>Date.now());let t=e.getSettings();this.rateLimiter=new sa({maxPerWindow:Math.max(1,t.channelRateLimitPerConversation),windowMs:Math.max(1e3,t.channelRateLimitWindowMinutes*6e4),now:this.now})}adapters=new Map;adapterConfigs=new Map;sessions=new Map;conversationLocks=new Map;rateLimiter;metrics=new Map;statusListeners=new Set;adapterUnsubscribes=new Map;now;threadBindings=new Map;activeTurns=new Map;turnTails=new Map;hibernationInterval=null;started=!1;async start(e){if(!this.started){this.started=!0;for(let t of e.channels)await this.bringUpChannel(t,e);this.hibernationInterval=window.setInterval(()=>{this.runHibernationSweep()},6e4)}}async stop(){if(!this.started)return;this.started=!1,this.hibernationInterval&&(window.clearInterval(this.hibernationInterval),this.hibernationInterval=null);let e=Array.from(this.adapters.values());await Promise.all(e.map(async t=>{try{await t.stop()}catch(s){console.warn(`Agent Fleet: channel adapter ${t.config.name} stop() failed`,s)}})),this.adapters.clear(),this.adapterConfigs.clear();for(let t of this.adapterUnsubscribes.values())for(let s of t)s();if(this.adapterUnsubscribes.clear(),this.conversationLocks.size>0&&await Promise.allSettled(Array.from(this.conversationLocks.values())),this.turnTails.size>0){let t=null,s=new Promise(n=>{t=window.setTimeout(n,1e4)});await Promise.race([Promise.allSettled(Array.from(this.turnTails.values())).then(()=>{}),s]),t!==null&&window.clearTimeout(t)}for(let t of this.sessions.values())try{t.session.isStreaming?t.session.abort():t.session.hibernate()}catch{}this.sessions.clear(),this.conversationLocks.clear(),this.conversationLockGen.clear(),this.rateLimiter.resetAll()}async reconcile(e){if(!this.started)return;let t=new Map;for(let s of e.channels)t.set(s.name,s);for(let[s,n]of this.adapters){let r=t.get(s),i=r&&this.isChannelRuntimeValid(r,e);if(!r||!r.enabled||!i){await this.tearDownChannel(s);continue}let o=this.adapterConfigs.get(s);o&&this.requiresRestart(o,r)?(await this.tearDownChannel(s),await this.bringUpChannel(r,e)):(this.adapterConfigs.set(s,r),n.config=r)}for(let[s,n]of t)!this.adapters.has(s)&&n.enabled&&this.isChannelRuntimeValid(n,e)&&await this.bringUpChannel(n,e);this.notifyStatusListeners()}getCredentials(){return this.deps.getChannelCredentials?.()??this.deps.getSettings().channelCredentials??{}}isChannelRuntimeValid(e,t){let s=t.agents.find(r=>r.name===e.defaultAgent);if(!s||s.approvalRequired.length>0)return!1;let n=this.getCredentials()[e.credentialRef];return!(!n||n.type!==e.type)}async bringUpChannel(e,t){if(!e.enabled||!this.isChannelRuntimeValid(e,t))return;let s=this.getCredentials()[e.credentialRef];if(!s)return;let n;try{n=this.deps.adapterFactory(e,s)}catch(i){console.error(`Agent Fleet: failed to build adapter for channel ${e.name}`,i);return}let r=[];r.push(n.onInbound(i=>{this.handleInbound(n,i)})),r.push(n.onStatusChange(()=>this.notifyStatusListeners())),n.onAgentSwitch&&r.push(n.onAgentSwitch((i,o,l)=>{let c=`${e.name}:${i}`;this.threadBindings.set(c,o),this.persistBindings(e.name)})),n.setAllowedAgentsResolver?.(()=>this.resolveAllowedAgents(e)),this.adapters.set(e.name,n),this.adapterConfigs.set(e.name,e),this.adapterUnsubscribes.set(e.name,r),this.ensureMetrics(e.name),await this.loadBindings(e.name);try{await n.start()}catch(i){console.error(`Agent Fleet: channel adapter ${e.name} start() failed`,i)}this.notifyStatusListeners()}async tearDownChannel(e){let t=this.adapters.get(e);if(!t)return;try{await t.stop()}catch(r){console.warn(`Agent Fleet: channel adapter ${e} stop() failed`,r)}let s=this.adapterUnsubscribes.get(e);if(s)for(let r of s)r();this.adapterUnsubscribes.delete(e),this.adapters.delete(e),this.adapterConfigs.delete(e);let n=`${e}:`;for(let[r,i]of this.sessions)if(r.startsWith(n)){try{i.session.isStreaming?i.session.abort():i.session.hibernate()}catch{}this.sessions.delete(r)}}requiresRestart(e,t){return e.type!==t.type||e.credentialRef!==t.credentialRef||JSON.stringify(e.transport)!==JSON.stringify(t.transport)}async handleInbound(e,t){let s=e.config,n=`${s.name}:${t.conversationId}`;if(!(s.allowedUsers.length>0&&(!t.externalUserId||!s.allowedUsers.includes(t.externalUserId)))){if(!this.rateLimiter.tryConsume(n)){console.warn(`Agent Fleet: rate-limited message from ${t.externalUserId} on ${s.name} (conversation ${t.conversationId})`);try{await e.send(t.conversationId,"_Rate limit exceeded. Please slow down and try again in a few minutes._")}catch(r){console.warn(`Agent Fleet: rate-limit reply failed on ${s.name} (user ${t.externalUserId}, conversation ${t.conversationId})`,r)}return}await this.withConversationLock(n,async()=>{let r=this.ensureMetrics(s.name);r.messagesReceived+=1,r.lastMessageAt=this.now();let i=this.resolveAllowedAgents(s),o=Xd(t.text,i),l,c;if(o){l=o.agent,c=o.rest;let m=this.threadBindings.get(n);if(this.threadBindings.set(n,l),this.persistBindings(s.name),m!==l)try{await e.setThreadTitle?.(t.conversationId,l)}catch{}if(!c){try{await e.send(t.conversationId,`_Now chatting with *${l}*. Send your next message to start._`)}catch{}return}}else{let m=`${s.name}:${t.conversationId.replace(/:thread:[^:]+$/,`:user:${t.externalUserId}`)}`;l=this.threadBindings.get(n)??this.threadBindings.get(m)??s.defaultAgent,c=t.text}if(t.images&&t.images.length>0){let m=await this.saveInboundImages(t.images);m&&(c=m+(c||"Please analyze this image."))}let d=this.activeTurns.get(n);if(d&&d.agent===l&&d.session.isStreaming){d.session.injectMessage(c);return}let u=await this.getOrCreateSession(s,t.conversationId,l),p=(this.turnTails.get(n)??Promise.resolve()).catch(()=>{}).then(()=>(this.activeTurns.set(n,{agent:l,session:u}),this.runChannelTurn(e,s,t.conversationId,l,u,c).finally(()=>{this.activeTurns.delete(n)})));this.turnTails.set(n,p),p.finally(()=>{this.turnTails.get(n)===p&&this.turnTails.delete(n)})})}}async runChannelTurn(e,t,s,n,r,i){let o=this.ensureMetrics(t.name),l=t.allowedAgents.length>1||t.allowedAgents.length===0&&this.resolveAllowedAgents(t).length>1;try{await e.setTyping(s,!0)}catch{}let c=Promise.resolve(),d=m=>{c=c.then(async()=>{try{await this.deliverReply(e,s,m),o.messagesSent+=1}catch(f){console.error(`Agent Fleet: reply delivery failed on ${t.name}`,f)}})},u="",h=[],p=()=>{let m=Jt(u).trim();if(h.length>0){let f=Qd(h);f&&(m+=`${m?`
|
|
11931
11927
|
|
|
11932
|
-
`:""}_${f}_`)}
|
|
11933
|
-
${m}`),
|
|
11934
|
-
The image file is located at: ${
|
|
11935
|
-
Please read and analyze this image.`)}catch(i){console.warn("Agent Fleet: failed to save inbound image",
|
|
11928
|
+
`:""}_${f}_`)}u="",h=[],m&&(l&&(m=`*[${n}]*
|
|
11929
|
+
${m}`),d(m))};try{await r.sendMessage(i,m=>{if(m.type==="text")u+=m.content;else if(m.type==="tool_use"&&m.toolName)h.push({name:m.toolName});else if(m.type==="error"){let f=m.errorMessage?.trim()||"the agent run failed";d(`_Sorry \u2014 ${f}_`)}else m.type==="result"&&p()})}catch(m){console.error(`Agent Fleet: channel turn failed on ${t.name}/${s}`,m),d(`_Sorry \u2014 the agent run failed. ${m instanceof Error?m.message:String(m)}_`)}finally{await c;try{await e.setTyping(s,!1)}catch{}this.enforceHardCap()}}async deliverReply(e,t,s){let n=Co(s);for(let r of n)await e.send(t,r)}async saveInboundImages(e){let s=`${this.deps.getSettings().fleetFolder}/chat-images`,n=[];for(let r of e)try{this.deps.vault.getAbstractFileByPath((0,xt.normalizePath)(s))||await this.deps.vault.createFolder((0,xt.normalizePath)(s));let i=(0,xt.normalizePath)(`${s}/${r.filename}`),o=i;if(this.deps.vault.getAbstractFileByPath(i)){let u=r.filename.lastIndexOf("."),h=u>0?r.filename.slice(0,u):r.filename,p=u>0?r.filename.slice(u):"";o=(0,xt.normalizePath)(`${s}/${h}_${Date.now()}${p}`)}await this.deps.vault.createBinary(o,r.data);let c=this.deps.vault.adapter.basePath??"",d=c?`${c}/${o}`:o;n.push(`### Image: ${r.filename}
|
|
11930
|
+
The image file is located at: ${d}
|
|
11931
|
+
Please read and analyze this image.`)}catch(i){console.warn("Agent Fleet: failed to save inbound image",r.filename,i)}return n.length===0?"":`## Attached Images
|
|
11936
11932
|
|
|
11937
11933
|
${n.join(`
|
|
11938
11934
|
|
|
@@ -11940,26 +11936,12 @@ ${n.join(`
|
|
|
11940
11936
|
|
|
11941
11937
|
---
|
|
11942
11938
|
|
|
11943
|
-
`}async getOrCreateSession(t,e,s){let n=`${t.name}:${e}:${s}`,a=this.sessions.get(n);if(a)return a.session;let i=this.deps.getRepository(),o=i.getAgentByName(s);if(!o)throw new Error(`Channel ${t.name} bound to missing agent ${s}`);let c=new Yt(o,this.deps.getSettings(),i,this.deps.vault,{channelName:t.name,conversationId:`${e}:${s}`,channelContext:t.channelContext||void 0,mcpAuth:this.deps.getMcpAuth?.()});this.deps.recordUsage&&c.setUsageRecorder(this.deps.recordUsage);try{await c.loadPersistedState()}catch{}return this.sessions.set(n,{session:c,channelName:t.name,conversationId:e,sessionKey:n}),c}resolveAllowedAgents(t){let e=new Set(this.deps.getRepository().getSnapshot().agents.filter(n=>n.enabled).map(n=>n.name));return(t.allowedAgents.length>0?t.allowedAgents:[...e]).filter(n=>e.has(n))}async persistBindings(t){let e=`${t}:`,s={};for(let[o,c]of this.threadBindings)o.startsWith(e)&&(s[o.slice(e.length)]=c);let n=this.deps.getSettings(),a=(0,ut.normalizePath)(`${n.fleetFolder}/channels/${t}/bindings.json`),i=JSON.stringify(s,null,2);try{let o=this.deps.vault.getAbstractFileByPath(a);if(o instanceof ut.TFile)await this.deps.vault.modify(o,i);else{let c=a.slice(0,a.lastIndexOf("/"));if(!this.deps.vault.getAbstractFileByPath(c))try{await this.deps.vault.createFolder(c)}catch{}await this.deps.vault.create(a,i)}}catch(o){console.warn(`Agent Fleet: failed to persist thread bindings for ${t}`,o)}}async loadBindings(t){let e=this.deps.getSettings(),s=(0,ut.normalizePath)(`${e.fleetFolder}/channels/${t}/bindings.json`);try{let n=this.deps.vault.getAbstractFileByPath(s);if(!(n instanceof ut.TFile))return;let a=await this.deps.vault.cachedRead(n),i=JSON.parse(a);for(let[o,c]of Object.entries(i))typeof c=="string"&&this.threadBindings.set(`${t}:${o}`,c)}catch{}}getThreadAgent(t,e){return this.threadBindings.get(`${t}:${e}`)}enforceHardCap(){let t=Math.max(1,this.deps.getSettings().maxConcurrentChannelSessions),e=Array.from(this.sessions.values()).filter(n=>n.session.isProcessAlive&&!n.session.isStreaming);if(e.length<=t)return;e.sort((n,a)=>n.session.lastActiveAt-a.session.lastActiveAt);let s=e.length-t;for(let n=0;n<s;n+=1){let a=e[n];if(!a)break;try{a.session.hibernate()}catch{}}}async runHibernationSweep(){let t=Math.max(6e4,this.deps.getSettings().channelIdleTimeoutMinutes*6e4),e=this.now()-t;for(let s of this.sessions.values())if(s.session.isProcessAlive&&!s.session.isStreaming&&s.session.lastActiveAt<e)try{s.session.hibernate()}catch{}}async broadcastToChannel(t,e){let s=this.adapters.get(t);if(!s){console.warn(`Agent Fleet: broadcastToChannel \u2014 no adapter for channel ${t}`);return}if(!s.broadcast){console.warn(`Agent Fleet: broadcastToChannel \u2014 adapter ${t} does not support broadcast`);return}await s.broadcast(e)}async postToChannelTarget(t,e,s){let n=this.adapters.get(t);if(!n){console.warn(`Agent Fleet: postToChannelTarget \u2014 no adapter for channel ${t}`);return}if(!n.sendToTarget){console.warn(`Agent Fleet: postToChannelTarget \u2014 adapter ${t} does not support sendToTarget`);return}await n.sendToTarget(e,s)}conversationLockGen=new Map;async withConversationLock(t,e){let s=this.conversationLocks.get(t)??Promise.resolve(),n,a=new Promise(o=>{n=o}),i=(this.conversationLockGen.get(t)??0)+1;this.conversationLockGen.set(t,i),this.conversationLocks.set(t,s.then(()=>a));try{await s,await e()}finally{n(),this.conversationLockGen.get(t)===i&&(this.conversationLocks.delete(t),this.conversationLockGen.delete(t))}}ensureMetrics(t){let e=this.metrics.get(t);return e||(e={messagesReceived:0,messagesSent:0,lastMessageAt:null},this.metrics.set(t,e)),e}getMetrics(t){return{...this.ensureMetrics(t)}}getChannelStatus(t){let e=this.adapters.get(t);return e?e.getStatus():"disabled"}getConnectedCount(){let t=0;for(let e of this.adapters.values())e.getStatus()==="connected"&&(t+=1);return t}getSessionCount(t){let e=0,s=`${t}:`;for(let n of this.sessions.keys())n.startsWith(s)&&(e+=1);return e}onStatusChange(t){return this.statusListeners.add(t),()=>this.statusListeners.delete(t)}notifyStatusListeners(){for(let t of this.statusListeners)try{t()}catch{}}};function wc(r){if(r.length===0)return"";let t=new Map;for(let s of r)t.set(s.name,(t.get(s.name)??0)+1);let e=[];for(let[s,n]of t)e.push(n>1?`${s}\xD7${n}`:s);return`Used ${r.length} tool${r.length===1?"":"s"}: ${e.join(", ")}`}var bn=class{credentials=new Map;secretStore;persistCallback;setSecretStore(t){this.secretStore=t}loadCredentials(t){if(this.credentials.clear(),this.secretStore?.available){let e=this.secretStore.listByPrefix(Vt);for(let s of e){let n=Vt+"-",a=s.startsWith(n)?s.slice(n.length):s,i=this.secretStore.getJson(Vt,a);if(i){let o=i._ref??a,c={...i};delete c._ref,this.credentials.set(o,c)}}}if(this.credentials.size===0&&t){for(let[e,s]of Object.entries(t))this.credentials.set(e,s);this.secretStore?.available&&this.credentials.size>0&&this.persistToSecretStore()}}onChanged(t){this.persistCallback=t}get(t){return this.credentials.get(t)}set(t,e){this.credentials.set(t,e),this.persist()}delete(t){this.credentials.delete(t),this.secretStore?.delete(Vt,t),this.persist()}list(){return Array.from(this.credentials.entries()).map(([t,e])=>({ref:t,entry:e}))}toRecord(){let t={};for(let[e,s]of this.credentials.entries())t[e]=s;return t}persist(){this.persistToSecretStore(),this.persistCallback&&this.persistCallback(this.toRecord())}persistToSecretStore(){if(this.secretStore?.available)for(let[t,e]of this.credentials)this.secretStore.setJson(Vt,t,{...e,_ref:t})}};function Si(){return{status:"disconnected",scope:"user",tools:[],toolDetails:[]}}function bc(r,t,e){if(e)return"stdio";let s=(r??"").toLowerCase();return s==="sse"?"sse":s==="http"||s==="streamable-http"||s==="streamable_http"?"http":t?.endsWith("/sse")?"sse":"http"}function Ci(r){let t=[],e={},s;try{s=JSON.parse(r)}catch{return{servers:t,tokens:e}}let n=s.mcpServers;if(!n||typeof n!="object")return{servers:t,tokens:e};for(let[a,i]of Object.entries(n)){if(!i||typeof i!="object")continue;let o=i,c=typeof o.command=="string"?o.command:void 0,l=typeof o.url=="string"?o.url:void 0;if(!c&&!l)continue;let h=bc(typeof o.type=="string"?o.type:void 0,l,!!c),d={name:a,type:h,enabled:!0,source:"imported",...Si()};if(h==="stdio")d.command=c,Array.isArray(o.args)&&(d.args=o.args.filter(u=>typeof u=="string")),o.env&&typeof o.env=="object"&&(d.env=xi(o.env));else{d.url=l;let u=o.headers&&typeof o.headers=="object"?xi(o.headers):{},p=u.Authorization??u.authorization;p?.startsWith("Bearer ")?(e[a]=p.slice(7),delete u.Authorization,delete u.authorization,d.auth="oauth"):d.auth="none",Object.keys(u).length>0&&(d.headers=u)}t.push(d)}return{servers:t,tokens:e}}function Ti(r){let t=new Map,e=null;for(let n of r.split(/\r?\n/)){let a=n.trim();if(!a||a.startsWith("#"))continue;let i=a.match(/^\[(.+)\]$/);if(i){let u=i[1].trim().match(/^mcp_servers\.(.+)$/);if(!u){e=null;continue}let p=u[1],m=null;p.endsWith(".env")?(m="env",p=p.slice(0,-4)):p.endsWith(".oauth")&&(m="oauth",p=p.slice(0,-6));let f=kn(p);if(!f){e=null;continue}t.has(f)||t.set(f,{name:f,enabled:!0}),e={name:f,sub:m};continue}if(!e)continue;let o=a.match(/^([^=]+?)\s*=\s*(.+)$/);if(!o)continue;let c=kn(o[1].trim()),l=o[2].trim(),h=t.get(e.name);if(e.sub==="env")h.env??={},h.env[c]=Kt(l);else if(e.sub==="oauth")c==="client_id"&&(h.oauthClientId=Kt(l));else switch(c){case"command":h.command=Kt(l);break;case"args":h.args=kc(l);break;case"url":h.url=Kt(l);break;case"bearer_token_env_var":h.bearerEnvVar=Kt(l);break;case"oauth_resource":h.oauthResource=Kt(l);break;case"enabled":h.enabled=l==="true";break;default:break}}let s=[];for(let n of t.values()){if(!n.command&&!n.url)continue;let a=n.command?"stdio":n.url?.endsWith("/sse")?"sse":"http",i={name:n.name,type:a,enabled:n.enabled,source:"imported",...Si()};a==="stdio"?(i.command=n.command,n.args&&n.args.length>0&&(i.args=n.args),n.env&&Object.keys(n.env).length>0&&(i.env=n.env)):(i.url=n.url,n.oauthClientId||n.oauthResource?(i.auth="oauth",i.oauth={clientId:n.oauthClientId,resource:n.oauthResource}):n.bearerEnvVar?(i.auth="bearer",i.envSecretKeys=[n.bearerEnvVar]):i.auth="none"),s.push(i)}return{servers:s,tokens:{}}}function _i(...r){let t=new Map,e={};for(let s of r){for(let n of s.servers){let a=n.name.trim().toLowerCase();t.has(a)||t.set(a,n)}Object.assign(e,s.tokens)}return{servers:[...t.values()],tokens:e}}function kn(r){let t=r.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Kt(r){let t=r.trim();if(t.startsWith('"')||t.startsWith("'")){let e=t[0],s=t.indexOf(e,1);if(s>0)return t.slice(1,s)}return kn(t.replace(/\s+#.*$/,""))}function kc(r){let t=r.trim();try{let s=JSON.parse(t);if(Array.isArray(s))return s.filter(n=>typeof n=="string")}catch{}return t.replace(/^\[/,"").replace(/\]$/,"").split(",").map(s=>kn(s.trim())).filter(Boolean)}function xi(r){let t={};for(let[e,s]of Object.entries(r))typeof s=="string"&&(t[e]=s);return t}var Wd=Ye(xo(),1),Hd=Ye(Rn(),1),qd=Ye(Qt(),1),zd=Ye(La(),1),Gd=Ye(Na(),1),Vd=Ye(Ha(),1),Do=Ye(Ln(),1),Yd=Ye(Ro(),1);var as=Do.default;var Io=require("obsidian");var Kd="https://slack.com/api";function Jd(r){let t=r.team??"unknown",e=r.channel??"unknown",s=r.thread_ts??r.ts??"unknown";return`slack:${t}:${e}:thread:${s}`}function Xd(r){let t=r.split(":");return t.length>=3&&t[0]==="slack"?t[2]??null:null}function Qd(r){let t=r.split(":");if(t[3]==="thread"&&t[4])return t[4]}var On=class{type="slack";config;credential;ws=null;status="stopped";stopping=!1;backoffMs=1e3;reconnectTimer=null;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;sendQueues=new Map;threadContext=new Map;constructor(t,e){if(e.type!=="slack")throw new Error(`SlackAdapter requires a slack credential, got ${e.type}`);this.config=t,this.credential=e}async start(){this.stopping=!1,await this.connect()}async stop(){if(this.stopping=!0,this.reconnectTimer&&(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws){try{this.ws.close()}catch{}this.ws=null}this.threadContext.clear(),this.sendQueues.clear(),this.setStatus("stopped")}getStatus(){return this.status}async send(t,e){let s=Xd(t);if(!s){console.warn(`Agent Fleet: could not extract channel id from ${t}`);return}let n=Qd(t),a=Ts(e);await this.enqueueSend(s,async()=>{await this.slackApi("chat.postMessage",{channel:s,text:a,...n?{thread_ts:n}:{}})})}async sendToTarget(t,e){if(!t)return;let s=Ts(e);await this.enqueueSend(t,async()=>{await this.slackApi("chat.postMessage",{channel:t,text:s})})}async broadcast(t){let e=this.config.allowedUsers[0];if(!e){console.warn(`Agent Fleet: broadcast on ${this.config.name} skipped \u2014 no allowed users configured`);return}try{let n=(await this.slackApi("conversations.open",{users:e})).channel?.id;if(!n){console.warn(`Agent Fleet: broadcast \u2014 conversations.open returned no channel for user ${e}`);return}let a=Ts(t);await this.slackApi("chat.postMessage",{channel:n,text:a})}catch(s){console.error(`Agent Fleet: broadcast failed on ${this.config.name}`,s)}}async setThreadTitle(t,e){let s=this.threadContext.get(t);if(s)try{await this.slackApi("assistant.threads.setTitle",{channel_id:s.channelId,thread_ts:s.threadTs,title:e})}catch(n){console.warn(`Agent Fleet: assistant.threads.setTitle failed on ${this.config.name}`,n)}}async setTyping(t,e){let s=this.threadContext.get(t);if(s)try{await this.slackApi("assistant.threads.setStatus",{channel_id:s.channelId,thread_ts:s.threadTs,status:e?"is thinking...":""})}catch(n){console.warn(`Agent Fleet: assistant.threads.setStatus (${e?"on":"off"}) failed on ${this.config.name}`,n)}}onInbound(t){return this.inboundHandlers.add(t),()=>this.inboundHandlers.delete(t)}onStatusChange(t){return this.statusHandlers.add(t),()=>this.statusHandlers.delete(t)}setAllowedAgentsResolver(t){this.allowedAgentsResolver=t}onAgentSwitch(t){return this.agentSwitchHandlers.add(t),()=>this.agentSwitchHandlers.delete(t)}async connect(){if(this.stopping)return;this.setStatus(this.ws?"reconnecting":"connecting");let t;try{let e=await this.slackApi("apps.connections.open",{},{useAppToken:!0});if(!e.ok||!e.url)throw new Error(e.error??"apps.connections.open returned no URL");t=e.url}catch(e){console.error(`Agent Fleet: Slack apps.connections.open failed for channel ${this.config.name}`,e),this.setStatus("needs-auth"),this.scheduleReconnect();return}try{let e=new as(t);e.on("open",()=>{}),e.on("message",a=>{this.handleSocketData(a)}),e.on("error",a=>{console.warn(`Agent Fleet: Slack WebSocket error on ${this.config.name}`,a),this.setStatus("error")}),e.on("close",()=>{this.ws=null,this.stopping||this.scheduleReconnect()}),this.ws=e;let s=window.setTimeout(()=>{if(this.status==="connecting"||this.status==="reconnecting"){console.warn(`Agent Fleet: Slack WebSocket connect timeout on ${this.config.name}`);try{e.close()}catch{}}},3e4);e.on("close",()=>window.clearTimeout(s));let n=this.onStatusChange(a=>{a==="connected"&&(window.clearTimeout(s),n())})}catch(e){console.error("Agent Fleet: Slack WebSocket open failed",e),this.setStatus("error"),this.scheduleReconnect();return}}handleSocketData(t){let e;try{e=JSON.parse(t.toString())}catch{return}if(e.type==="hello"){this.backoffMs=1e3,this.setStatus("connected");return}if(e.type==="disconnect"){try{this.ws?.close()}catch{}return}if(e.type==="events_api"&&e.envelope_id){this.ackEnvelope(e.envelope_id),this.routeEventPayload(e.payload);return}if(e.type==="slash_commands"&&e.envelope_id){this.ackEnvelope(e.envelope_id),this.handleSlashCommand(e.payload);return}if(e.type==="interactive"&&e.envelope_id){this.ackEnvelope(e.envelope_id),this.handleInteraction(e.payload);return}e.envelope_id&&this.ackEnvelope(e.envelope_id)}async handleSlashCommand(t){if(!t)return;let e=t.command,s=t.channel_id,n=t.user_id;if(!(!e||!s||!n)){if(e==="/agents"){let a=this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents;if(a.length===0){await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file."});return}let i=a.map(c=>({type:"button",text:{type:"plain_text",text:c===this.config.defaultAgent?`${c} \u2713`:c,emoji:!0},action_id:`switch_agent_${c}`,value:c})),o=[{type:"section",text:{type:"mrkdwn",text:"*Select an agent to chat with:*"}}];for(let c=0;c<i.length;c+=5)o.push({type:"actions",elements:i.slice(c,c+5)});try{await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:"Select an agent",blocks:o})}catch(c){console.error("Agent Fleet: /agents response failed",c)}return}try{await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:`Unknown command: ${e}`})}catch(a){console.error(`Agent Fleet: slash command response failed for ${e}`,a)}}}async handleInteraction(t){if(!t||t.type!=="block_actions")return;let s=t.actions,n=t.user,a=t.channel;if(!s?.length||!n||!a)return;let i=s[0];if(!i)return;let o=i.action_id,c=i.value;if(!o?.startsWith("switch_agent_")||!c)return;let l=n.id,h=a.id;if(!l||!h)return;let u=`slack:${t.team?.id??"unknown"}:${h}:user:${l}`;for(let p of this.agentSwitchHandlers)try{p(u,c,l)}catch(m){console.error("Agent Fleet: agent switch handler threw",m)}try{await this.slackApi("chat.postEphemeral",{channel:h,user:l,text:`Switched to *${c}*. Send your next message to start.`})}catch(p){console.warn("Agent Fleet: agent switch confirmation failed",p)}try{await this.setThreadTitle(u,c)}catch{}}ackEnvelope(t){if(!(!this.ws||this.ws.readyState!==as.OPEN))try{this.ws.send(JSON.stringify({envelope_id:t}))}catch(e){console.warn("Agent Fleet: Slack envelope ACK failed",e)}}routeEventPayload(t){if(!t)return;let e=t.event;if(!e)return;let s=e.type;if(s==="assistant_thread_started"){let h=e.assistant_thread;h?.channel_id&&h.thread_ts&&console.debug(`Agent Fleet: assistant thread started on ${this.config.name} (channel=${h.channel_id}, thread_ts=${h.thread_ts}, user=${h.user_id})`);return}if(s==="assistant_thread_context_changed")return;let n=e,a=s==="message"&&n.subtype===void 0,i=s==="app_mention";if(!a&&!i||n.bot_id||!n.user||!n.text||i&&(n.text=n.text.replace(/^<@[A-Z0-9]+>\s*/,"").trim(),!n.text))return;let o=Jd(n),c=n.thread_ts??n.ts;if(n.channel&&c&&(this.threadContext.set(o,{channelId:n.channel,threadTs:c}),this.threadContext.size>500)){let d=this.threadContext.keys().next();d.done||this.threadContext.delete(d.value)}let l={conversationId:o,externalUserId:n.user,text:n.text,timestamp:new Date().toISOString(),meta:{slack_channel:n.channel,slack_ts:n.ts,thread_ts:n.thread_ts}};for(let h of this.inboundHandlers)try{h(l)}catch(d){console.error("Agent Fleet: Slack inbound handler threw",d)}}scheduleReconnect(){if(this.stopping||this.reconnectTimer)return;let t=this.backoffMs;this.backoffMs=Math.min(3e4,this.backoffMs*2),console.warn(`Agent Fleet: Slack channel ${this.config.name} scheduling reconnect in ${t}ms`),this.reconnectTimer=window.setTimeout(()=>{this.reconnectTimer=null,!this.stopping&&this.connect()},t)}setStatus(t){if(this.status!==t){this.status=t;for(let e of this.statusHandlers)try{e(t)}catch{}}}async slackApi(t,e,s={}){let n=s.useAppToken?this.credential.appToken:this.credential.botToken,a=`${Kd}/${t}`,i=await(0,Io.requestUrl)({url:a,method:"POST",contentType:"application/json; charset=utf-8",headers:{Authorization:`Bearer ${n}`},body:JSON.stringify(e),throw:!1});if(i.status===429){let c=Number(i.headers["retry-after"]??"1");return await new Promise(l=>window.setTimeout(l,Math.max(1e3,c*1e3))),this.slackApi(t,e,s)}if(i.status<200||i.status>=300)throw new Error(`Slack ${t} HTTP ${i.status}`);let o=i.json;if(o.ok===!1)throw new Error(`Slack ${t} error: ${o.error??"unknown"}`);return o}async enqueueSend(t,e){let n=(this.sendQueues.get(t)??Promise.resolve()).then(async()=>{try{await e()}finally{await new Promise(i=>window.setTimeout(i,1e3))}}),a=n.catch(i=>{console.warn(`Agent Fleet: Slack send queue error for ${t}`,i)});this.sendQueues.set(t,a),await n,this.sendQueues.get(t)===a&&this.sendQueues.delete(t)}};var Ga=require("obsidian"),Mo="https://api.telegram.org",Nn=class{type="telegram";config;credential;status="stopped";stopping=!1;pollOffset=0;pollTimer=null;backoffMs=1e3;typingIntervals=new Map;pollAbort=null;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;constructor(t,e){if(e.type!=="telegram")throw new Error(`TelegramAdapter requires a telegram credential, got ${e.type}`);this.config=t,this.credential=e}async start(){this.stopping=!1;try{let e=(await this.tgApi("getUpdates",{offset:-1,limit:1})).result?.[0];e&&(this.pollOffset=e.update_id+1)}catch{}try{await this.tgApi("setMyCommands",{commands:[{command:"agents",description:"List available agents"}]})}catch{}this.setStatus("connected"),this.poll()}async stop(){this.stopping=!0,this.pollTimer&&(window.clearTimeout(this.pollTimer),this.pollTimer=null),this.pollAbort?.abort(),this.pollAbort=null;for(let[,t]of this.typingIntervals)window.clearInterval(t);this.typingIntervals.clear(),this.setStatus("stopped")}getStatus(){return this.status}async send(t,e){let s=Lo(t);if(!s)return;let n=Fo(t),a=za(e,4096);for(let i of a)await this.tgApi("sendMessage",{chat_id:s,text:i,parse_mode:"Markdown",...n?{message_thread_id:Number(n)}:{}})}async sendToTarget(t,e){if(!t)return;let s=za(e,4096);for(let n of s)await this.tgApi("sendMessage",{chat_id:t,text:n,parse_mode:"Markdown"})}async setTyping(t,e){let s=Lo(t);if(!s)return;let n=Fo(t),a={chat_id:s,action:"typing"};if(n&&(a.message_thread_id=Number(n)),e){let i=this.typingIntervals.get(t);i&&window.clearInterval(i);try{await this.tgApi("sendChatAction",a)}catch(c){console.warn("Agent Fleet: Telegram sendChatAction failed",c)}let o=window.setInterval(()=>{this.tgApi("sendChatAction",a).catch(()=>{})},4500);this.typingIntervals.set(t,o)}else{let i=this.typingIntervals.get(t);i&&(window.clearInterval(i),this.typingIntervals.delete(t))}}async setThreadTitle(t,e){}async broadcast(t){let e=this.config.allowedUsers[0];if(e)try{let s=za(t,4096);for(let n of s)await this.tgApi("sendMessage",{chat_id:e,text:n,parse_mode:"Markdown"})}catch(s){console.error(`Agent Fleet: Telegram broadcast failed on ${this.config.name}`,s)}}onInbound(t){return this.inboundHandlers.add(t),()=>this.inboundHandlers.delete(t)}onStatusChange(t){return this.statusHandlers.add(t),()=>this.statusHandlers.delete(t)}setAllowedAgentsResolver(t){this.allowedAgentsResolver=t}pickerAgents(){return this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents}onAgentSwitch(t){return this.agentSwitchHandlers.add(t),()=>this.agentSwitchHandlers.delete(t)}poll(){this.stopping||(async()=>{try{this.pollAbort=new AbortController;let t=await this.tgApi("getUpdates",{offset:this.pollOffset,timeout:30,allowed_updates:["message","callback_query"]},this.pollAbort.signal);if(t.ok&&t.result)for(let e of t.result){if(this.pollOffset=e.update_id+1,e.callback_query){this.handleCallbackQuery(e.callback_query);continue}e.message&&this.routeMessage(e.message)}this.backoffMs=1e3,this.status!=="connected"&&this.setStatus("connected")}catch(t){if(t instanceof DOMException&&t.name==="AbortError")return;if(console.warn(`Agent Fleet: Telegram poll failed on ${this.config.name}`,t),this.status!=="error"&&this.status!=="needs-auth"){let e=t instanceof Error?t.message:String(t);this.setStatus(e.includes("401")||e.includes("Unauthorized")?"needs-auth":"error")}await new Promise(e=>window.setTimeout(e,this.backoffMs)),this.backoffMs=Math.min(3e4,this.backoffMs*2)}this.stopping||(this.pollTimer=window.setTimeout(()=>this.poll(),100))})()}routeMessage(t){let e=t.photo&&t.photo.length>0,s=t.document&&this.isImageMime(t.document.mime_type),n=!!t.text;if(!t.from||!n&&!e&&!s)return;let a=t.text??t.caption??"";if(a==="/agents"||a.startsWith("/agents@")){this.handleAgentsCommand(t);return}if(a.startsWith("/"))return;let i=String(t.from.id),o=String(t.chat.id),c=t.message_thread_id?String(t.message_thread_id):void 0,l=c?`tg:${o}:topic:${c}`:`tg:${o}`;this.buildAndEmitMessage(t,a,l,i,o,c)}async buildAndEmitMessage(t,e,s,n,a,i){let o=[];try{if(t.photo&&t.photo.length>0){let l=t.photo[t.photo.length-1],h=await this.downloadFile(l.file_id,`photo_${t.message_id}.jpg`,"image/jpeg");h&&o.push(h)}if(t.document&&this.isImageMime(t.document.mime_type)){let l=t.document.file_name??`doc_${t.message_id}`,h=t.document.mime_type??"image/jpeg",d=await this.downloadFile(t.document.file_id,l,h);d&&o.push(d)}}catch(l){console.warn("Agent Fleet: Telegram image download failed",l)}let c={conversationId:s,externalUserId:n,text:e,timestamp:new Date(t.date*1e3).toISOString(),meta:{telegram_chat_id:a,telegram_message_id:t.message_id,telegram_thread_id:i,chat_type:t.chat.type},...o.length>0?{images:o}:{}};for(let l of this.inboundHandlers)try{l(c)}catch(h){console.error("Agent Fleet: Telegram inbound handler threw",h)}}async downloadFile(t,e,s){let a=(await this.tgApi("getFile",{file_id:t})).result?.file_path;if(!a)return null;let i=`${Mo}/file/bot${this.credential.botToken}/${a}`;return{data:(await(0,Ga.requestUrl)({url:i,method:"GET"})).arrayBuffer,filename:e,mimeType:s}}isImageMime(t){return t?t==="image/jpeg"||t==="image/png"||t==="image/gif"||t==="image/webp"||t==="image/bmp"||t==="image/tiff":!1}async handleAgentsCommand(t){let e=String(t.chat.id),s=t.message_thread_id,n=this.pickerAgents();if(n.length===0){await this.tgApi("sendMessage",{chat_id:e,text:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file.",...s?{message_thread_id:s}:{}});return}let a=n.map(i=>[{text:i===this.config.defaultAgent?`${i} \u2713`:i,callback_data:`switch:${i}`}]);await this.tgApi("sendMessage",{chat_id:e,text:"*Select an agent to chat with:*",parse_mode:"Markdown",reply_markup:{inline_keyboard:a},...s?{message_thread_id:s}:{}})}async handleCallbackQuery(t){let e=t.data;if(!e?.startsWith("switch:")){await this.tgApi("answerCallbackQuery",{callback_query_id:t.id});return}let s=e.slice(7),n=String(t.from.id),a=String(t.message?.chat?.id??t.from.id),i=t.message?.message_thread_id?String(t.message.message_thread_id):void 0,o=i?`tg:${a}:topic:${i}`:`tg:${a}`;for(let c of this.agentSwitchHandlers)try{c(o,s,n)}catch(l){console.error("Agent Fleet: Telegram agent switch handler threw",l)}if(await this.tgApi("answerCallbackQuery",{callback_query_id:t.id,text:`Switched to ${s}`}),t.message){let l=this.pickerAgents().map(h=>[{text:h===s?`${h} \u2713`:h,callback_data:`switch:${h}`}]);try{await this.tgApi("editMessageText",{chat_id:a,message_id:t.message.message_id,text:`*Active agent: ${s}*`,parse_mode:"Markdown",reply_markup:{inline_keyboard:l}})}catch{}}}async tgApi(t,e,s){if(s?.aborted)throw new DOMException("Aborted","AbortError");let n=`${Mo}/bot${this.credential.botToken}/${t}`,a=(0,Ga.requestUrl)({url:n,method:"POST",contentType:"application/json",body:JSON.stringify(e),throw:!1}),i;if(s?i=await Promise.race([a,new Promise((o,c)=>{s.addEventListener("abort",()=>c(new DOMException("Aborted","AbortError")),{once:!0})})]):i=await a,i.status===401||i.status===403)throw new Error(`Telegram ${t} ${i.status} Unauthorized`);if(i.status===429){let c=i.json?.parameters?.retry_after??1;return await new Promise(l=>window.setTimeout(l,c*1e3)),this.tgApi(t,e)}if(i.status<200||i.status>=300)throw new Error(`Telegram ${t} HTTP ${i.status}: ${i.text}`);return i.json}setStatus(t){if(this.status!==t){this.status=t;for(let e of this.statusHandlers)try{e(t)}catch{}}}};function Lo(r){return r.startsWith("tg:")?r.split(":")[1]??null:null}function Fo(r){let t=r.split(":");if(t[2]==="topic"&&t[3])return t[3]}function za(r,t){if(r.length<=t)return[r];let e=[],s=r;for(;s.length>t;){let n=s.lastIndexOf(`
|
|
11944
|
-
|
|
11945
|
-
`,
|
|
11946
|
-
`,t)),n<t/2&&(n=t),e.push(s.slice(0,n)),s=s.slice(n).replace(/^\n+/,"")}return s&&e.push(s),e}var Ya=require("obsidian"),Zd="https://discord.com/api/v10",eh="wss://gateway.discord.gg",th="?v=10&encoding=json",sh="DiscordBot (https://github.com/denberek/obsidian-agent-fleet, 0.13.6)",nh=37376,ah=0,Va=1,rh=2,ih=6,oh=7,lh=9,ch=10,dh=11,hh=2,uh=3,Oo=4,ph=7,No=64,Bn=class{type="discord";config;credential;ws=null;status="stopped";stopping=!1;backoffMs=1e3;reconnectTimer=null;sessionId=null;resumeGatewayUrl=null;seq=null;canResume=!1;heartbeatTimer=null;heartbeatInitialTimer=null;heartbeatAcked=!0;selfUserId=null;applicationId=null;commandRegistered=!1;warnedEmptyContent=!1;typingIntervals=new Map;sendQueues=new Map;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;constructor(t,e){if(e.type!=="discord")throw new Error(`DiscordAdapter requires a discord credential, got ${e.type}`);this.config=t,this.credential=e}async start(){this.stopping=!1,this.backoffMs=1e3,this.canResume=!1,await this.connect()}async stop(){this.stopping=!0,this.reconnectTimer&&(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.clearHeartbeat();for(let[,t]of this.typingIntervals)window.clearInterval(t);this.typingIntervals.clear();try{this.ws?.close()}catch{}this.ws=null,this.setStatus("stopped")}getStatus(){return this.status}async send(t,e){let s=Uo(t);s&&await this.sendToTarget(s,e)}async sendToTarget(t,e){if(!t)return;let s=$o(e,2e3);await this.enqueueSend(t,async()=>{for(let n of s)await this.discordApi("POST",`/channels/${t}/messages`,{content:n})})}async setTyping(t,e){let s=Uo(t);if(s)if(e){let n=this.typingIntervals.get(t);n&&window.clearInterval(n);try{await this.discordApi("POST",`/channels/${s}/typing`)}catch(i){console.warn("Agent Fleet: Discord typing trigger failed",i)}let a=window.setInterval(()=>{this.discordApi("POST",`/channels/${s}/typing`).catch(()=>{})},8e3);this.typingIntervals.set(t,a)}else{let n=this.typingIntervals.get(t);n&&(window.clearInterval(n),this.typingIntervals.delete(t))}}async broadcast(t){let e=this.config.allowedUsers[0];if(e)try{let n=(await this.discordApi("POST","/users/@me/channels",{recipient_id:e}))?.id;if(!n)return;let a=$o(t,2e3);for(let i of a)await this.discordApi("POST",`/channels/${n}/messages`,{content:i})}catch(s){console.error(`Agent Fleet: Discord broadcast failed on ${this.config.name}`,s)}}onInbound(t){return this.inboundHandlers.add(t),()=>this.inboundHandlers.delete(t)}onStatusChange(t){return this.statusHandlers.add(t),()=>this.statusHandlers.delete(t)}onAgentSwitch(t){return this.agentSwitchHandlers.add(t),()=>this.agentSwitchHandlers.delete(t)}setAllowedAgentsResolver(t){this.allowedAgentsResolver=t}pickerAgents(){return this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents}async connect(){if(this.stopping)return;this.setStatus(this.ws?"reconnecting":"connecting");let e=`${this.canResume&&this.resumeGatewayUrl?this.resumeGatewayUrl:eh}${th}`;try{let s=new as(e);s.on("message",i=>{this.handleFrame(i)}),s.on("error",i=>{console.warn(`Agent Fleet: Discord WebSocket error on ${this.config.name}`,i)}),s.on("close",i=>{this.ws=null,this.clearHeartbeat(),this.handleClose(i)}),this.ws=s;let n=window.setTimeout(()=>{if(this.status==="connecting"||this.status==="reconnecting"){console.warn(`Agent Fleet: Discord WebSocket connect timeout on ${this.config.name}`);try{s.close()}catch{}}},3e4);s.on("close",()=>window.clearTimeout(n));let a=this.onStatusChange(i=>{i==="connected"&&(window.clearTimeout(n),a())})}catch(s){console.error("Agent Fleet: Discord WebSocket open failed",s),this.setStatus("error"),this.scheduleReconnect()}}handleClose(t){let e=!1;t===4014?(console.error(`Agent Fleet: Discord channel ${this.config.name} \u2014 disallowed intents (4014). Enable the Message Content intent in the Developer Portal \u2192 your app \u2192 Bot \u2192 Privileged Gateway Intents, then reload.`),this.canResume=!1,this.setStatus("needs-auth"),e=!0):t===4004||t===4013?(console.error(`Agent Fleet: Discord channel ${this.config.name} \u2014 gateway auth/intents error (${t}). Check the bot token credential, then reload.`),this.canResume=!1,this.setStatus("needs-auth"),e=!0):(t===4007||t===4009)&&(this.canResume=!1),!this.stopping&&!e&&this.scheduleReconnect()}handleFrame(t){let e;try{e=JSON.parse(t.toString())}catch{return}switch(typeof e.s=="number"&&(this.seq=e.s),e.op){case ch:{let s=e.d?.heartbeat_interval;this.startHeartbeat(s??41250),this.canResume&&this.sessionId&&this.seq!==null?this.sendGateway(ih,{token:this.credential.botToken,session_id:this.sessionId,seq:this.seq}):this.identify();return}case Va:{this.sendGateway(Va,this.seq);return}case dh:{this.heartbeatAcked=!0;return}case oh:{try{this.ws?.close()}catch{}return}case lh:{e.d===!0||(this.canResume=!1,this.sessionId=null),window.setTimeout(()=>{try{this.ws?.close()}catch{}},1e3+Math.floor(Math.random()*4e3));return}case ah:{this.handleDispatch(e.t??"",e.d);return}default:return}}handleDispatch(t,e){if(t==="READY"){let s=e;this.sessionId=s.session_id??null,this.resumeGatewayUrl=s.resume_gateway_url??null,this.selfUserId=s.user?.id??null,this.applicationId=s.application?.id??null,this.canResume=!0,this.backoffMs=1e3,this.setStatus("connected"),this.registerAgentsCommand();return}if(t==="RESUMED"){this.backoffMs=1e3,this.setStatus("connected");return}if(t==="MESSAGE_CREATE"){this.routeMessage(e);return}if(t==="INTERACTION_CREATE"){this.handleInteraction(e);return}}identify(){this.sendGateway(rh,{token:this.credential.botToken,intents:nh,properties:{os:"linux",browser:"agent-fleet",device:"agent-fleet"}})}sendGateway(t,e){if(!(!this.ws||this.ws.readyState!==as.OPEN))try{this.ws.send(JSON.stringify({op:t,d:e}))}catch(s){console.warn("Agent Fleet: Discord gateway send failed",s)}}startHeartbeat(t){this.clearHeartbeat(),this.heartbeatAcked=!0;let e=()=>{if(!this.heartbeatAcked){console.warn(`Agent Fleet: Discord heartbeat not ACKed on ${this.config.name} \u2014 reconnecting`);try{this.ws?.close()}catch{}return}this.heartbeatAcked=!1,this.sendGateway(Va,this.seq)};this.heartbeatInitialTimer=window.setTimeout(()=>{e(),this.heartbeatTimer=window.setInterval(e,t)},Math.floor(t*Math.random()))}clearHeartbeat(){this.heartbeatInitialTimer&&(window.clearTimeout(this.heartbeatInitialTimer),this.heartbeatInitialTimer=null),this.heartbeatTimer&&(window.clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}scheduleReconnect(){if(this.stopping||this.reconnectTimer)return;let t=this.backoffMs;this.backoffMs=Math.min(3e4,this.backoffMs*2),console.warn(`Agent Fleet: Discord channel ${this.config.name} scheduling reconnect in ${t}ms`),this.reconnectTimer=window.setTimeout(()=>{this.reconnectTimer=null,!this.stopping&&this.connect()},t)}routeMessage(t){if(!t.author||t.author.bot||this.selfUserId&&t.author.id===this.selfUserId||!t.channel_id)return;let e=(t.attachments??[]).filter(a=>typeof a.content_type=="string"&&a.content_type.startsWith("image/")),s=mh(t.content??"",this.selfUserId);if(!s&&e.length===0){this.warnedEmptyContent||(this.warnedEmptyContent=!0,console.warn(`Agent Fleet: Discord channel ${this.config.name} received a message with empty content. If this persists, enable the Message Content intent in the Developer Portal.`));return}let n=Bo(t.guild_id,t.channel_id);this.buildAndEmitMessage(t,s,n,e)}async buildAndEmitMessage(t,e,s,n){let a=[];for(let o of n)try{let c=await(0,Ya.requestUrl)({url:o.url,method:"GET"});a.push({data:c.arrayBuffer,filename:o.filename||`attachment_${t.id}`,mimeType:o.content_type??"image/jpeg"})}catch(c){console.warn("Agent Fleet: Discord attachment download failed",c)}let i={conversationId:s,externalUserId:t.author.id,text:e,timestamp:t.timestamp??new Date().toISOString(),meta:{discord_guild_id:t.guild_id,discord_channel_id:t.channel_id,discord_message_id:t.id,is_dm:!t.guild_id},...a.length>0?{images:a}:{}};for(let o of this.inboundHandlers)try{o(i)}catch(c){console.error("Agent Fleet: Discord inbound handler threw",c)}}async registerAgentsCommand(){if(!(this.commandRegistered||!this.applicationId))try{await this.discordApi("PUT",`/applications/${this.applicationId}/commands`,[{name:"agents",description:"Switch the active agent",type:1}]),this.commandRegistered=!0}catch(t){console.warn(`Agent Fleet: Discord /agents command registration failed on ${this.config.name}`,t)}}async handleInteraction(t){if(t.type===hh){t.data?.name==="agents"&&await this.respondWithAgentPicker(t);return}if(t.type===uh){let e=t.data?.custom_id??"";if(!e.startsWith("switch:"))return;let s=e.slice(7),n=t.member?.user?.id??t.user?.id,a=t.channel_id;if(!n||!a)return;let i=Bo(t.guild_id,a);for(let o of this.agentSwitchHandlers)try{o(i,s,n)}catch(c){console.error("Agent Fleet: Discord agent switch handler threw",c)}await this.respondToInteraction(t,ph,{content:`Active agent: **${s}**`,components:this.buildAgentButtons(s)});return}}async respondWithAgentPicker(t){if(this.pickerAgents().length===0){await this.respondToInteraction(t,Oo,{content:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file.",flags:No});return}await this.respondToInteraction(t,Oo,{content:"Select an agent to chat with:",flags:No,components:this.buildAgentButtons(this.config.defaultAgent)})}buildAgentButtons(t){let e=this.pickerAgents().slice(0,25),s=[];for(let n=0;n<e.length;n+=5){let a=e.slice(n,n+5);s.push({type:1,components:a.map(i=>({type:2,style:i===t?1:2,label:i===t?`${i} \u2713`:i,custom_id:`switch:${i}`}))})}return s}async respondToInteraction(t,e,s){try{await this.discordApi("POST",`/interactions/${t.id}/${t.token}/callback`,{type:e,data:s})}catch(n){console.warn("Agent Fleet: Discord interaction response failed",n)}}async discordApi(t,e,s){let n=await(0,Ya.requestUrl)({url:`${Zd}${e}`,method:t,contentType:"application/json",headers:{Authorization:`Bot ${this.credential.botToken}`,"User-Agent":sh},...s!==void 0?{body:JSON.stringify(s)}:{},throw:!1});if(n.status===429){let a=n.json?.retry_after??Number(n.headers["retry-after"]??"1");return await new Promise(i=>window.setTimeout(i,Math.max(1e3,a*1e3))),this.discordApi(t,e,s)}if(n.status===401||n.status===403)throw new Error(`Discord ${t} ${e} ${n.status}: ${fh(n.text)}`);if(n.status<200||n.status>=300)throw new Error(`Discord ${t} ${e} HTTP ${n.status}: ${n.text}`);if(n.status!==204)return n.json}async enqueueSend(t,e){let n=(this.sendQueues.get(t)??Promise.resolve()).then(e),a=n.catch(()=>{});this.sendQueues.set(t,a);try{await n}finally{this.sendQueues.get(t)===a&&this.sendQueues.delete(t)}}setStatus(t){if(this.status!==t){this.status=t;for(let e of this.statusHandlers)try{e(t)}catch{}}}};function Bo(r,t){return r?`discord:${r}:${t}`:`discord:dm:${t}`}function Uo(r){let t=r.split(":");return t[0]!=="discord"?null:t[2]??null}function mh(r,t){let e=r.trimStart();if(t){let s=new RegExp(`^<@!?${t}>\\s*`);e=e.replace(s,"")}return e.trim()}function fh(r){let t=r??"";try{let e=JSON.parse(t);if(e&&(e.message!==void 0||e.code!==void 0))return`${e.message??"error"} (code ${e.code??"?"})`}catch{}return t||"no body"}function $o(r,t){if(r.length<=t)return[r];let e=[],s=r;for(;s.length>t;){let n=s.lastIndexOf(`
|
|
11947
|
-
|
|
11948
|
-
`,t);n<t/2&&(n=s.lastIndexOf(`
|
|
11949
|
-
`,t)),n<t/2&&(n=t),e.push(s.slice(0,n)),s=s.slice(n).replace(/^\n+/,"")}return s&&e.push(s),e}var Ms=require("obsidian");var Un=class extends Ms.ItemView{constructor(e,s){super(e);this.plugin=s}getViewType(){return jt}getDisplayText(){return"Agent Fleet"}getIcon(){return"bot"}async onOpen(){this.plugin.subscribeView(this),await this.render()}async onClose(){this.plugin.unsubscribeView(this)}async render(){let e=this.contentEl;e.empty(),e.addClass("af-sidebar");let s=this.plugin.runtime.getSnapshot(),n=this.plugin.runtime.getFleetStatus(),a=e.createDiv({cls:"af-sidebar-section"});a.createDiv({cls:"af-sidebar-section-header",text:"AGENT FLEET"});let i=[{icon:"layout-dashboard",label:"Dashboard",page:"dashboard"},{icon:"bot",label:"Agents",page:"agents",badge:()=>s.agents.length},{icon:"columns-3",label:"Tasks Board",page:"kanban"},{icon:"scroll-text",label:"Run History",page:"runs"},{icon:"shield-check",label:"Approvals",page:"approvals",badge:()=>n.pending},{icon:"puzzle",label:"Skills",page:"skills",badge:()=>s.skills.length},{icon:"plug",label:"MCP Servers",page:"mcp",badge:()=>this.plugin.repository.getMcpServers().length},{icon:"radio",label:"Channels",page:"channels",badge:()=>this.plugin.channelManager?.getConnectedCount()??s.channels.length}];for(let l of i){let h=a.createDiv({cls:"af-sidebar-nav-item"}),d=h.createSpan({cls:"af-sidebar-nav-icon"});(0,Ms.setIcon)(d,l.icon),h.createSpan({cls:"af-sidebar-nav-label",text:l.label});let u=l.badge?.();u!==void 0&&u>0&&h.createSpan({cls:"af-sidebar-badge",text:String(u)}),h.setAttribute("role","button"),h.setAttribute("tabindex","0"),h.onclick=()=>void this.plugin.navigateDashboard(l.page),h.onkeydown=p=>{(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),this.plugin.navigateDashboard(l.page))}}let o=e.createDiv({cls:"af-sidebar-section"});o.createDiv({cls:"af-sidebar-section-header",text:"AGENTS"}),s.agents.length===0&&o.createDiv({cls:"af-sidebar-empty",text:"No agents configured"});for(let l of s.agents){let h=this.plugin.runtime.getAgentState(l.name),d=o.createDiv({cls:"af-sidebar-agent-item"});d.createSpan({cls:`af-sidebar-agent-dot ${this.healthToClass(h.status)}`}),d.createSpan({cls:"af-sidebar-agent-name",text:l.name}),d.setAttribute("role","button"),d.setAttribute("tabindex","0"),d.onclick=()=>void this.plugin.navigateDashboard("agent-detail",l.name),d.onkeydown=u=>{(u.key==="Enter"||u.key===" ")&&(u.preventDefault(),this.plugin.navigateDashboard("agent-detail",l.name))}}let c=e.createDiv({cls:"af-sidebar-section"});c.createDiv({cls:"af-sidebar-section-header",text:"QUICK ACTIONS"}),this.renderQuickAction(c,"plus","New Agent",()=>void this.plugin.createAgentTemplate()),this.renderQuickAction(c,"plus","New Task",()=>void this.plugin.openCreateTask()),this.renderQuickAction(c,"plus","New Skill",()=>void this.plugin.createSkillTemplate())}renderQuickAction(e,s,n,a){let i=e.createDiv({cls:"af-sidebar-action-item"}),o=i.createSpan({cls:"af-sidebar-action-icon"});(0,Ms.setIcon)(o,s),i.createSpan({text:n}),i.setAttribute("role","button"),i.setAttribute("tabindex","0"),i.onclick=a,i.onkeydown=c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),a())}}healthToClass(e){switch(e){case"running":return"running";case"error":return"error";case"pending":return"pending";case"disabled":return"disabled";default:return"idle"}}};var b=require("obsidian");var rs=require("obsidian"),gh=["bot","brain","shield-check","search","file-text","rocket","wand","sparkles","zap","target","compass","eye","code","terminal","database","globe","mail","message-circle","book","pen-tool","palette","music","camera","chart-bar","clipboard","cpu","server","cloud","lock","key","bell","calendar","clock","heart","star","flag","bookmark"],$n=class extends rs.Modal{constructor(e,s,n){super(e);this.onSelect=n;this.selectedIcon=s}searchQuery="";selectedIcon;allIcons=[];gridContainer;onOpen(){this.allIcons=(0,rs.getIconIds)().sort();let{contentEl:e}=this;e.empty(),e.addClass("af-icon-picker-modal");let s=e.createEl("input",{cls:"af-icon-picker-search",attr:{type:"text",placeholder:"Search icons...",value:this.searchQuery}});this.gridContainer=e.createDiv({cls:"af-icon-picker-scroll"}),this.renderGrid(),s.addEventListener("input",()=>{this.searchQuery=s.value,this.renderGrid()}),window.setTimeout(()=>s.focus(),0)}renderGrid(){let e=this.gridContainer;e.empty();let s=this.searchQuery.toLowerCase().trim();if(!s)this.renderSection(e,"Popular",gh),this.renderSection(e,"All Icons",this.allIcons);else{let n=this.allIcons.filter(i=>i.includes(s)),a=n.length===0?"No results":`${n.length} result${n.length!==1?"s":""}`;this.renderSection(e,a,n)}}renderSection(e,s,n){let a=e.createDiv({cls:"af-icon-picker-section"});a.createDiv({cls:"af-icon-picker-section-label",text:s});let i=a.createDiv({cls:"af-icon-picker-grid"});for(let o of n)this.renderIconItem(i,o)}renderIconItem(e,s){let n=e.createDiv({cls:`af-icon-picker-item${this.selectedIcon===s?" selected":""}`});n.setAttribute("title",s),n.setAttribute("aria-label",s),(0,rs.setIcon)(n,s),n.addEventListener("click",()=>{this.selectedIcon=s,this.onSelect(s),this.close()})}onClose(){this.contentEl.empty()}};var yh=[{match:/opus/i,rates:{input:15,output:75,cacheWrite:18.75,cacheRead:1.5}},{match:/sonnet/i,rates:{input:3,output:15,cacheWrite:3.75,cacheRead:.3}},{match:/haiku/i,rates:{input:1,output:5,cacheWrite:1.25,cacheRead:.1}},{match:/gpt-5|codex|o[0-9]/i,rates:{input:1.25,output:10,cacheWrite:1.25,cacheRead:.125}}],vh={input:3,output:15,cacheWrite:3.75,cacheRead:.3};function jo(r){for(let{match:t,rates:e}of yh)if(t.test(r))return e;return vh}function Wo(r,t){let e=jo(r);return(t.inputTokens*e.input+t.outputTokens*e.output+t.cacheCreateTokens*e.cacheWrite+t.cacheReadTokens*e.cacheRead)/1e6}function Ho(r,t){let e=jo(r),s=.7*e.input+.3*e.output;return t*s/1e6}var qo=require("obsidian");function R(r,t,e){let s=r.createSpan({cls:e??"af-icon"});return(0,qo.setIcon)(s,t),s}function Ze(r,t={}){let e=activeDocument.createElementNS("http://www.w3.org/2000/svg",r);for(let[s,n]of Object.entries(t))e.setAttribute(s,n);return e}function wh(r){try{return new Date(r+"T12:00:00").toLocaleDateString(void 0,{month:"short",day:"numeric"})}catch{return r.slice(5)}}function zo(r,t){let e=t.length||1,s=1e3,n=6,a=4,i=4,o=s-a-i-n*(e-1),c=Math.floor(o/e),l=140,h=36,d=18,u=d+l+h,p=Math.max(1,...t.map(f=>f.success+f.failure+f.cancelled)),m=Ze("svg",{viewBox:`0 0 ${s} ${u}`,width:"100%",height:String(u),class:"af-chart-bar"});for(let f=0;f<=4;f++){let g=d+l-f/4*l;m.appendChild(Ze("line",{x1:String(a),y1:String(g),x2:String(s-i),y2:String(g),stroke:"var(--af-text-faint)","stroke-opacity":"0.15","stroke-width":"1"}))}for(let f=0;f<t.length;f++){let g=t[f],y=a+f*(c+n),v=g.success+g.failure+g.cancelled,k=v/p*l,w=g.success/p*l,S=g.cancelled/p*l,T=g.failure/p*l;if(g.success>0&&m.appendChild(Ze("rect",{x:String(y),y:String(d+l-w),width:String(c),height:String(Math.max(w,2)),fill:"var(--af-green)",opacity:"0.85"})),g.cancelled>0&&m.appendChild(Ze("rect",{x:String(y),y:String(d+l-w-S),width:String(c),height:String(Math.max(S,2)),fill:"var(--af-yellow)",opacity:"0.85"})),g.failure>0&&m.appendChild(Ze("rect",{x:String(y),y:String(d+l-k),width:String(c),height:String(Math.max(T,2)),fill:"var(--af-red)",opacity:"0.85"})),v===0&&m.appendChild(Ze("rect",{x:String(y),y:String(d+l-3),width:String(c),height:"3",rx:"1.5",fill:"var(--af-text-faint)",opacity:"0.2"})),v>0){let D=Ze("text",{x:String(y+c/2),y:String(d+l-k-5),"text-anchor":"middle","font-size":"10","font-weight":"600",fill:"var(--af-text-secondary)"});D.textContent=String(v),m.appendChild(D)}let _=Ze("text",{x:String(y+c/2),y:String(d+l+16),"text-anchor":"middle","font-size":"10",fill:"var(--af-text-muted)"});_.textContent=wh(g.date),m.appendChild(_)}r.appendChild(m)}function Go(r,t,e){let c=2*Math.PI*46,l=e>0?t/e:0,h=c*l,d=c-h,u=Ze("svg",{viewBox:"0 0 130 130",width:String(130),height:String(130),class:"af-chart-donut"});u.appendChild(Ze("circle",{cx:String(65),cy:String(65),r:String(46),fill:"none",stroke:e>0?"var(--af-red)":"var(--af-text-faint)","stroke-width":String(12),opacity:"0.2"})),l>0&&u.appendChild(Ze("circle",{cx:String(65),cy:String(65),r:String(46),fill:"none",stroke:"var(--af-green)","stroke-width":String(12),"stroke-dasharray":`${h} ${d}`,"stroke-dashoffset":String(c*.25),"stroke-linecap":"round"}));let p=Ze("text",{x:String(65),y:String(61),"text-anchor":"middle","dominant-baseline":"middle","font-size":"24","font-weight":"700",fill:"var(--af-text-primary)"});p.textContent=`${Math.round(l*100)}%`,u.appendChild(p);let m=Ze("text",{x:String(65),y:String(83),"text-anchor":"middle","font-size":"10",fill:"var(--af-text-muted)"});m.textContent=`${t}/${e} runs`,u.appendChild(m),r.appendChild(u)}function Vo(r,t){r.draggable=!0,r.addEventListener("dragstart",e=>{e.dataTransfer?.setData("text/plain",t),r.addClass("af-dragging")}),r.addEventListener("dragend",()=>{r.removeClass("af-dragging")})}function Yo(r,t){r.addEventListener("dragover",e=>{e.preventDefault(),r.addClass("af-drag-over")}),r.addEventListener("dragleave",e=>{let s=e.relatedTarget;(!s||!r.contains(s))&&r.removeClass("af-drag-over")}),r.addEventListener("drop",e=>{e.preventDefault();let s=e.dataTransfer?.getData("text/plain");r.removeClass("af-drag-over"),s&&t(s)})}function Ko(r){let t=/^##\s+Lint\s+(\d{4}-\d{2}-\d{2})\s*$/gm,e,s=-1,n="";for(;(e=t.exec(r))!==null;)e.index>s&&(s=e.index,n=e[1]??"");if(s<0)return null;let a=r.slice(s),i=a.search(/\n##\s+(?!\s*#)/),o=i<0?a:a.slice(0,i);return{date:n,summary:jn(o,"Summary"),autoApplied:jn(o,"Auto-applied"),needsReview:jn(o,"Needs review"),refreshChained:jn(o,"Refresh chained")}}function jn(r,t){let e=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^###\\s+${e}\\s*$`,"m").exec(r);if(!n)return[];let a=n.index+n[0].length,i=r.slice(a),o=i.search(/\n###\s+/),l=(o<0?i:i.slice(0,o)).split(/\r?\n/).map(d=>d.trimEnd()),h=[];for(let d of l){let u=d.replace(/^\s+/,"");u.startsWith("- ")?h.push(u.slice(2).trim()):h.length>0&&(d.startsWith(" ")||d.startsWith(" "))&&(h[h.length-1]+=" "+u)}return h}var Jo={dashboard:"Dashboard",agents:"Agents",kanban:"Tasks Board",runs:"Run History",skills:"Skills Library",approvals:"Approvals",mcp:"MCP Servers",channels:"Channels","wiki-keepers":"Wiki Keepers","agent-detail":"Agent Details","task-detail":"Task Details","create-agent":"Create Agent","create-task":"Create Task","create-skill":"Create Skill","edit-agent":"Edit Agent","edit-task":"Edit Task","edit-skill":"Edit Skill","create-channel":"Create Channel","edit-channel":"Edit Channel","add-mcp-server":"Add MCP Server"},bh={dashboard:"layout-dashboard",agents:"bot",kanban:"columns-3",runs:"scroll-text",skills:"puzzle",approvals:"shield-check",mcp:"plug",channels:"radio","wiki-keepers":"library","agent-detail":"bot","task-detail":"circle-dot","create-agent":"plus","create-task":"plus","create-skill":"plus","edit-agent":"edit","edit-task":"edit","edit-skill":"edit","create-channel":"plus","edit-channel":"edit","add-mcp-server":"plus"},kh=["dashboard","agents","kanban","runs","approvals","skills","wiki-keepers","mcp","channels"],Xo=[["claude-code","Claude Code",!1],["codex","Codex",!1],["process","Process (coming soon)",!0],["http","HTTP (coming soon)",!0]],Zo=[["bypassPermissions","Bypass Permissions","Auto-approve everything except deny list"],["dontAsk","Don\u2019t Ask","Auto-approve all tool calls"],["acceptEdits","Accept Edits","Auto-approve file edits, block bash unless allowed"],["plan","Plan","Read-only mode, no writes or commands"],["default","Default","Ask for each tool call"]],el=[["bypassPermissions","Bypass (no sandbox)","No sandbox, auto-approve everything"],["workspace-write","Workspace Write","Sandboxed: writes only inside the working dir"],["read-only","Read Only","Sandboxed: no writes or side-effect commands"]];function Ls(r){let t=r.trim().toLowerCase();return t==="codex"||t==="openai-codex"}function Wn(r){return Ls(r)?el:Zo}function Hn(r,t){if(Ls(t))switch(r){case"acceptEdits":case"default":return"workspace-write";case"plan":return"read-only";case"dontAsk":return"bypassPermissions";default:return el.some(([e])=>e===r)?r:"bypassPermissions"}switch(r){case"workspace-write":return"acceptEdits";case"read-only":return"plan";case"danger-full-access":return"bypassPermissions";default:return Zo.some(([e])=>e===r)?r:"bypassPermissions"}}var Fs=class extends b.ItemView{constructor(e,s){super(e);this.plugin=s}currentPage="dashboard";detailContext;agentDetailTab="overview";streamingUnsubscribes=[];channelStatusUnsubscribe;authenticatingServers=new Set;getViewType(){return _t}getDisplayText(){return"Agent Fleet"}getIcon(){return"bot"}async onOpen(){this.plugin.subscribeView(this),this.channelStatusUnsubscribe=this.plugin.channelManager?.onStatusChange(()=>{this.currentPage==="channels"&&this.render()}),await this.render()}async onClose(){this.cleanupStreaming(),this.channelStatusUnsubscribe?.(),this.channelStatusUnsubscribe=void 0,this.plugin.unsubscribeView(this)}navigateTo(e,s){this.currentPage=e,this.detailContext=s,e!=="agent-detail"&&(this.agentDetailTab="overview"),this.render()}async render(){this.cleanupStreaming();let e=this.contentEl;e.empty(),e.addClass("af-root");let n=e.createDiv({cls:"af-app"}).createDiv({cls:"af-main-content"});this.renderTopBar(n),this.renderTabBar(n);let a=n.createDiv({cls:"af-page"});switch(this.currentPage){case"dashboard":this.renderDashboardPage(a);break;case"agents":this.renderAgentsPage(a);break;case"kanban":this.renderKanbanPage(a);break;case"runs":this.renderRunsPage(a);break;case"skills":this.renderSkillsPage(a);break;case"approvals":this.renderApprovalsPage(a);break;case"mcp":this.renderMcpPage(a);break;case"channels":this.renderChannelsPage(a);break;case"wiki-keepers":this.renderWikiKeepersPage(a);break;case"agent-detail":this.renderAgentDetailPage(a);break;case"task-detail":this.renderTaskDetailPage(a);break;case"create-agent":this.renderCreateAgentPage(a);break;case"create-task":this.renderCreateTaskPage(a);break;case"create-skill":this.renderCreateSkillPage(a);break;case"edit-agent":this.renderEditAgentPage(a);break;case"edit-task":this.renderEditTaskPage(a);break;case"edit-skill":this.renderEditSkillPage(a);break;case"create-channel":this.renderCreateChannelPage(a);break;case"edit-channel":this.renderEditChannelPage(a);break;case"add-mcp-server":this.renderAddMcpServerPage(a);break}}navigate(e,s){this.navigateTo(e,s)}cleanupStreaming(){for(let e of this.streamingUnsubscribes)e();this.streamingUnsubscribes=[]}renderTopBar(e){let s=e.createDiv({cls:"af-top-bar"}),n=s.createDiv({cls:"af-top-bar-title"});R(n,"bot","af-top-bar-icon"),n.createSpan({text:"Agent Fleet"});let a=s.createDiv({cls:"af-breadcrumb"}),i=a.createSpan({cls:"af-breadcrumb-sep"});(0,b.setIcon)(i,"chevron-right");let o=(m,f,g)=>{let y=a.createSpan({cls:f?"af-breadcrumb-link":"",text:m});f&&(y.onclick=()=>this.navigate(f,g))},c=()=>{let m=a.createSpan({cls:"af-breadcrumb-sep"});(0,b.setIcon)(m,"chevron-right")};switch(this.currentPage){case"agent-detail":o("Agents","agents"),c(),o(this.detailContext??"Agent");break;case"task-detail":o("Tasks Board","kanban"),c(),o(this.detailContext??"Task");break;case"edit-agent":o("Agents","agents"),c(),o(this.detailContext??"Agent","agent-detail",this.detailContext),c(),o("Edit");break;case"edit-task":o("Tasks Board","kanban"),c(),o(this.detailContext??"Task","task-detail",this.detailContext),c(),o("Edit");break;case"create-agent":o("Agents","agents"),c(),o("New Agent");break;case"create-task":o("Tasks Board","kanban"),c(),o("New Task");break;case"create-skill":o("Skills Library","skills"),c(),o("New Skill");break;case"edit-skill":o("Skills Library","skills"),c(),o(this.detailContext??"Skill"),c(),o("Edit");break;case"create-channel":o("Channels","channels"),c(),o("New Channel");break;case"edit-channel":o("Channels","channels"),c(),o(this.detailContext??"Channel"),c(),o("Edit");break;case"add-mcp-server":o("MCP Servers","mcp"),c(),o("Add Server");break;default:o(Jo[this.currentPage])}s.createDiv({cls:"af-top-bar-spacer"});let l=s.createDiv({cls:"af-search-wrap"});R(l,"search","af-search-icon");let h=l.createEl("input",{cls:"af-search-input",attr:{type:"text",placeholder:"Search agents, tasks, runs..."}});h.addEventListener("input",()=>{this.handleSearch(h.value,l)}),h.addEventListener("blur",()=>{window.setTimeout(()=>l.querySelector(".af-search-results")?.remove(),200)});let d=this.plugin.runtime.getFleetStatus(),u=s.createDiv({cls:"af-status-pills"});if(d.running>0){let m=u.createSpan({cls:"af-pill yellow"});m.createSpan({cls:"af-dot pulse"}),m.appendText(` ${d.running} Running`)}if(d.pending>0){let m=u.createSpan({cls:"af-pill blue"});m.createSpan({cls:"af-dot"}),m.appendText(` ${d.pending} Pending`)}let p=u.createSpan({cls:"af-pill green"});p.createSpan({cls:"af-dot"}),p.appendText(` ${d.completedToday} Today`)}renderTabBar(e){let s=e.createDiv({cls:"af-tab-bar"}),n=this.plugin.runtime.getSnapshot(),a=this.plugin.runtime.getFleetStatus();for(let i of kh){let o=this.currentPage===i||i==="agents"&&(this.currentPage==="agent-detail"||this.currentPage==="edit-agent"||this.currentPage==="create-agent")||i==="kanban"&&(this.currentPage==="task-detail"||this.currentPage==="edit-task")||i==="skills"&&(this.currentPage==="edit-skill"||this.currentPage==="create-skill")||i==="mcp"&&this.currentPage==="add-mcp-server",c=s.createEl("button",{cls:`af-tab-item${o?" active":""}`}),l=c.createSpan({cls:"af-tab-icon"});if((0,b.setIcon)(l,bh[i]),c.appendText(i==="dashboard"?"Overview":Jo[i]),i==="agents")c.createSpan({cls:"af-badge",text:String(n.agents.length)});else if(i==="skills")c.createSpan({cls:"af-badge",text:String(n.skills.length)});else if(i==="mcp"){let h=this.plugin.repository.getMcpServers().length;c.createSpan({cls:"af-badge",text:String(h)})}else i==="approvals"&&a.pending>0&&c.createSpan({cls:"af-badge af-badge-warn",text:String(a.pending)});c.onclick=()=>this.navigate(i)}}renderDashboardPage(e){let s=e.createDiv({cls:"af-dashboard"}),n=this.plugin.runtime.getSnapshot(),a=this.plugin.runtime.getRecentRuns(),i=this.plugin.runtime.getFleetStatus(),o=a.filter(S=>(S.approvals??[]).some(T=>T.status==="pending"));for(let S of o)for(let T of S.approvals??[])T.status==="pending"&&this.renderApprovalBanner(s,S,T.tool);let c=s.createDiv({cls:"af-dash-grid"}),l=n.agents.filter(S=>S.enabled).length,h=n.agents.length;this.renderStatCard(c,"Active Agents",`${l}`,`/ ${h}`,"bot",`${l} of ${h} enabled`);let d=this.toLocalDateStr(new Date),u=a.filter(S=>this.runToLocalDate(S.started)===d),p=u.filter(S=>S.status==="success").length,m=u.filter(S=>S.status==="failure"||S.status==="timeout").length;this.renderStatCard(c,"Runs Today",String(u.length),"","activity",`${p} passed \xB7 ${m} failed \xB7 ${i.running} running`);let f=this.plugin.runtime.getUsageRecords().filter(S=>this.runToLocalDate(S.ts)===d),{tokens:g,cost:y}=this.combinedTotals(u,f),v=y>0?` \xB7 $${y.toFixed(2)}`:"";this.renderStatCard(c,"Tokens Used",Ka(g),"","zap",`today${v}`);let k=n.tasks.filter(S=>S.enabled&&S.schedule);this.renderStatCard(c,"Scheduled Tasks",String(k.length),"","clock",k.length>0?`Next: ${this.getNextTaskLabel(k)}`:"No scheduled tasks"),this.renderChartsRow(s,a,this.plugin.runtime.getChartRuns()),this.renderStreamingCards(s);let w=s.createDiv({cls:"af-dash-split"});this.renderActivityTimeline(w,a),this.renderFleetStatusPanel(w,n)}renderChartsRow(e,s,n){let a=e.createDiv({cls:"af-charts-row"}),i=a.createDiv({cls:"af-section-card af-chart-section"}),c=i.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(c,"activity"),c.appendText(" Run Activity (14d)");let l=i.createDiv({cls:"af-chart-body"}),h=this.buildChartData(n,14);h.some(y=>y.success+y.failure+y.cancelled>0)?zo(l,h):this.renderEmptyState(l,"activity","No run data","Run agents to see activity");let d=a.createDiv({cls:"af-section-card af-chart-section"}),p=d.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(p,"target"),p.appendText(" Success Rate");let m=d.createDiv({cls:"af-chart-body af-chart-body-center"}),f=s.length,g=s.filter(y=>y.status==="success").length;f>0?Go(m,g,f):this.renderEmptyState(m,"target","No data","")}toLocalDateStr(e){let s=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${s(e.getMonth()+1)}-${s(e.getDate())}`}runToLocalDate(e){return this.toLocalDateStr(new Date(e))}runCost(e){return e.costUsd??Ho(e.model,e.tokensUsed??0)}usageCost(e){return e.costUsd??Wo(e.model,{inputTokens:e.inputTokens,outputTokens:e.outputTokens,cacheReadTokens:e.cacheReadTokens,cacheCreateTokens:e.cacheCreateTokens})}combinedTotals(e,s){let n=e.reduce((i,o)=>i+(o.tokensUsed??0),0)+s.reduce((i,o)=>i+o.totalTokens,0),a=e.reduce((i,o)=>i+this.runCost(o),0)+s.reduce((i,o)=>i+this.usageCost(o),0);return{tokens:n,cost:a}}buildChartData(e,s){let n=[],a=new Date;for(let i=s-1;i>=0;i--){let o=new Date(a);o.setDate(o.getDate()-i);let c=this.toLocalDateStr(o),l=e.filter(h=>this.runToLocalDate(h.started)===c);n.push({date:c,success:l.filter(h=>h.status==="success").length,failure:l.filter(h=>h.status==="failure"||h.status==="timeout").length,cancelled:l.filter(h=>h.status==="cancelled").length})}return n}renderStreamingCards(e){let n=this.plugin.runtime.getSnapshot().agents.filter(c=>this.plugin.runtime.getAgentState(c.name).status==="running");if(n.length===0)return;let a=e.createDiv({cls:"af-streaming-section"}),o=a.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(o,"terminal"),o.appendText(" Active Agents");for(let c of n)this.renderStreamingCard(a,c.name)}renderStreamingCard(e,s){let n=e.createDiv({cls:"af-streaming-card"}),a=this.plugin.runtime.getAgentState(s),i=this.plugin.runtime.getSnapshot(),o=a.currentTaskId?i.tasks.find(m=>m.taskId===a.currentTaskId):void 0,c=o?` \u2192 ${o.taskId}`:a.currentTaskId?.startsWith("reflection-")?" \u2192 Reflection":a.currentTaskId?.startsWith("heartbeat-")||a.status==="running"?" \u2192 Heartbeat":"",l=n.createDiv({cls:"af-streaming-card-header"});l.createSpan({cls:"af-dot pulse",attr:{style:"background: var(--af-yellow)"}}),l.createSpan({cls:"af-streaming-card-agent",text:` ${s}`}),c&&l.createSpan({cls:"af-streaming-card-task",text:c});let h=n.createDiv({cls:"af-streaming-output"}),d=a.currentTaskId?.startsWith("reflection-")?"Consolidating memory\u2026":"Working\u2026",u=m=>{let f=ye(m).filter(g=>g.trim().length>0).slice(-4);h.setText(f.length>0?f.join(`
|
|
11950
|
-
`):d)};u(this.plugin.runtime.getRunOutputBuffer(s));let p=this.plugin.runtime.onRunOutput(s,()=>{u(this.plugin.runtime.getRunOutputBuffer(s)),h.scrollTop=h.scrollHeight});this.streamingUnsubscribes.push(p)}renderApprovalBanner(e,s,n){let a=e.createDiv({cls:"af-approval-banner"}),i=a.createDiv({cls:"af-approval-icon"});(0,b.setIcon)(i,"shield-check");let o=a.createDiv({cls:"af-approval-text"});o.createDiv({cls:"af-approval-title",text:`${s.agent} wants to run: ${n}`}),o.createDiv({cls:"af-approval-desc",text:`Approval required for tool: ${n}`});let c=a.createDiv({cls:"af-approval-actions"}),l=c.createEl("button",{cls:"af-btn-approve",text:"Approve"});l.onclick=()=>void this.plugin.runtime.resolveApproval(s,n,"approved").then(()=>this.render());let h=c.createEl("button",{cls:"af-btn-reject",text:"Reject"});h.onclick=()=>void this.plugin.runtime.resolveApproval(s,n,"rejected").then(()=>this.render())}renderStatCard(e,s,n,a,i,o){let c=e.createDiv({cls:"af-stat-card"}),l=c.createDiv({cls:"af-stat-label"});R(l,i,"af-stat-icon"),l.appendText(` ${s}`);let h=c.createDiv({cls:"af-stat-value"});h.appendText(n),a&&h.createSpan({cls:"af-stat-value-suffix",text:a}),c.createDiv({cls:"af-stat-sub",text:o})}renderActivityTimeline(e,s){let n=e.createDiv({cls:"af-section-card"}),i=n.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(i,"inbox"),i.appendText(" Recent Activity");let o=n.createDiv({cls:"af-timeline"}),c=s.slice(0,8);if(c.length===0){this.renderEmptyState(o,"inbox","No runs yet","Run an agent to see activity here");return}for(let l of c)this.renderTimelineItem(o,l)}renderTimelineItem(e,s){let n=e.createDiv({cls:"af-timeline-item"}),a=this.statusToTimelineClass(s.status),i=n.createDiv({cls:`af-tl-icon ${a}`});(0,b.setIcon)(i,this.statusToIconName(s.status));let o=n.createDiv({cls:"af-tl-body"}),c=o.createDiv({cls:"af-tl-title"});c.createSpan({cls:"af-agent-tag",text:s.agent}),c.appendText(` ${s.task}`),o.createDiv({cls:"af-tl-desc",text:Wt(s.output,100)});let l=o.createDiv({cls:"af-tl-meta"}),h=l.createSpan();if(R(h,"clock","af-meta-icon"),h.appendText(` ${this.formatStarted(s.started)} \xB7 ${this.formatDuration(s.durationSeconds)}`),s.tokensUsed){let d=l.createSpan();R(d,"zap","af-meta-icon"),d.appendText(` ${s.tokensUsed.toLocaleString()} tokens`)}n.onclick=()=>this.openSlideover(s)}renderFleetStatusPanel(e,s){let n=e.createDiv({cls:"af-section-card"}),a=n.createDiv({cls:"af-section-header"}),i=a.createDiv({cls:"af-section-title"});R(i,"bot"),i.appendText(" Fleet Status");let c=a.createDiv({cls:"af-section-actions"}).createEl("button",{cls:"af-btn-sm primary"});R(c,"plus","af-btn-icon"),c.appendText(" New Agent"),c.onclick=()=>void this.plugin.createAgentTemplate();let l=n.createDiv({cls:"af-agent-mini-list"});if(s.agents.length===0){this.renderEmptyState(l,"bot","No agents yet","Create your first agent to get started");return}for(let d of s.agents)this.renderAgentMini(l,d,s.tasks);let h=s.agents.filter(d=>d.enabled);if(h.length>0){let d=n.createDiv({cls:"af-quick-run"}),u=d.createDiv({cls:"af-quick-run-label"});R(u,"zap","af-meta-icon"),u.appendText(" Quick Run");let p=d.createDiv({cls:"af-quick-run-row"}),m=p.createEl("select",{cls:"af-select"});for(let g of h)m.createEl("option",{text:g.name,attr:{value:g.name}});let f=p.createEl("button",{cls:"af-btn-sm primary"});R(f,"play","af-btn-icon"),f.appendText(" Run"),f.onclick=()=>void this.plugin.runAgentPrompt(m.value)}}renderAgentMini(e,s,n){let a=this.plugin.runtime.getAgentState(s.name),i=n.filter(u=>u.agent===s.name),o=this.healthToClass(a.status),c=e.createDiv({cls:"af-agent-mini"}),l=c.createDiv({cls:`af-agent-avatar ${o}`});s.avatar?.trim()?this.renderAgentAvatar(l,s):l.setText(this.getInitials(s.name));let h=c.createDiv({cls:"af-agent-info"});h.createDiv({cls:"af-agent-name",text:s.name});let d="";if(a.status==="running")d=`Running now \xB7 ${i.length} task${i.length!==1?"s":""}`;else if(!s.enabled)d=`Disabled \xB7 ${i.length} task${i.length!==1?"s":""} paused`;else{let u=i.map(p=>p.nextRun).filter(Boolean).sort()[0];d=u?`Next: ${this.formatNextRun(u)} \xB7 ${i.length} task${i.length!==1?"s":""}`:`${i.length} task${i.length!==1?"s":""}`}h.createDiv({cls:"af-agent-desc",text:d}),c.createDiv({cls:`af-agent-status-dot ${o}`}),c.onclick=()=>this.navigate("agent-detail",s.name)}renderAgentsPage(e){let s=e.createDiv({cls:"af-agents-page"}),n=this.plugin.runtime.getSnapshot(),a=s.createDiv({cls:"af-agents-toolbar"});a.createDiv({cls:"af-page-title",text:"Agents"}),a.createDiv({cls:"af-toolbar-spacer"});let i=a.createEl("button",{cls:"af-btn-sm primary"});R(i,"plus","af-btn-icon"),i.appendText(" New Agent"),i.onclick=()=>void this.plugin.createAgentTemplate();let o=s.createDiv({cls:"af-agents-grid"});if(n.agents.length===0){this.renderEmptyState(o,"bot","No agents configured","Create your first agent to get started");return}for(let c of n.agents)this.renderAgentCard(o,c,n)}renderAgentCard(e,s,n){let a=this.plugin.runtime.getAgentState(s.name),i=this.plugin.runtime.getRecentRuns().filter(D=>D.agent===s.name),o=e.createDiv({cls:`af-agent-card${s.enabled?"":" disabled"}`}),c=o.createDiv({cls:"af-agent-card-header"}),l=s.enabled?this.healthToClass(a.status):"disabled",h=c.createDiv({cls:`af-agent-card-avatar ${l}`});this.renderAgentAvatar(h,s);let d=c.createDiv({cls:"af-agent-card-titleblock"}),u=d.createDiv({cls:"af-agent-card-name"});if(u.appendText(s.name),s.heartbeatEnabled&&s.heartbeatSchedule){let D=u.createSpan({cls:"af-heartbeat-indicator"});(0,b.setIcon)(D,"heart-pulse"),D.title=`Heartbeat: ${s.heartbeatSchedule}`}d.createDiv({cls:"af-agent-card-desc",text:s.description??"No description"});let p=c.createDiv({cls:`af-agent-card-toggle${s.enabled?" on":""}`});p.onclick=D=>{D.stopPropagation(),this.plugin.toggleAgent(s.name,!s.enabled)};let m=o.createDiv({cls:"af-agent-card-stats"}),f=i.length,g=i.filter(D=>D.status==="success").length,y=f>0?Math.round(g/f*100):0,v=f>0?Math.round(i.reduce((D,O)=>D+O.durationSeconds,0)/f):0,k=i.reduce((D,O)=>D+(O.tokensUsed??0),0);if(this.renderAgentStat(m,String(f),"Runs"),this.renderAgentStat(m,`${y}%`,"Success"),this.renderAgentStat(m,`${v}s`,"Avg Time"),this.renderAgentStat(m,Ka(k),"Tokens"),s.skills.length>0){let D=o.createDiv({cls:"af-agent-card-skills"});for(let O of s.skills)D.createSpan({cls:"af-skill-tag",text:O})}let w=o.createDiv({cls:"af-agent-card-footer"}),S=[`Model: ${s.model}`];s.approvalRequired.length>0&&S.push(`Approval: ${s.approvalRequired.join(", ")}`),s.memory&&S.push("Memory: on"),s.enabled||S.unshift("Disabled"),w.createSpan({cls:"af-agent-card-meta",text:S.join(" \xB7 ")});let T=w.createDiv({cls:"af-agent-card-actions"});if(!s.enabled){let D=T.createEl("button",{cls:"af-btn-sm",text:"Enable"});D.onclick=O=>{O.stopPropagation(),this.plugin.toggleAgent(s.name,!0)}}let _=T.createEl("button",{cls:"af-btn-sm"});if(R(_,"edit","af-btn-icon"),_.appendText(" Edit"),_.onclick=D=>{D.stopPropagation(),this.navigate("edit-agent",s.name)},s.enabled){let D=T.createEl("button",{cls:"af-btn-sm primary"});R(D,"play","af-btn-icon"),D.appendText(" Run"),D.onclick=O=>{O.stopPropagation(),this.plugin.runAgentPrompt(s.name)}}o.onclick=()=>this.navigate("agent-detail",s.name)}renderAgentStat(e,s,n){let a=e.createDiv({cls:"af-agent-stat"});a.createSpan({cls:"af-agent-stat-value",text:s}),a.createSpan({cls:"af-agent-stat-label",text:n})}renderAgentDetailPage(e){let s=e.createDiv({cls:"af-agent-detail-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"bot","No agent selected","Select an agent from the list");return}let a=this.plugin.runtime.getSnapshot().agents.find(k=>k.name===n);if(!a){this.renderEmptyState(s,"bot","Agent not found",`Agent "${n}" was not found`);return}let i=this.plugin.runtime.getAgentState(a.name),o=this.plugin.runtime.getRecentRuns().filter(k=>k.agent===a.name),c=s.createDiv({cls:"af-detail-header"}),l=c.createDiv({cls:"af-detail-header-left"}),h=l.createDiv({cls:`af-agent-card-avatar ${this.healthToClass(i.status)}`});this.renderAgentAvatar(h,a);let d=l.createDiv();d.createDiv({cls:"af-detail-header-name",text:a.name}),d.createDiv({cls:"af-detail-header-desc",text:a.description??"No description"});let u=c.createDiv({cls:"af-detail-header-actions"}),p=u.createEl("button",{cls:"af-btn-sm primary"});if(R(p,"message-circle","af-btn-icon"),p.appendText(" Chat"),p.onclick=()=>this.openChatSlideover(a),a.enabled){let k=u.createEl("button",{cls:"af-btn-sm"});R(k,"play","af-btn-icon"),k.appendText(" Run Now"),k.onclick=()=>void this.plugin.runAgentPrompt(a.name);let w=u.createEl("button",{cls:"af-btn-sm"});R(w,"pause","af-btn-icon"),w.appendText(" Disable"),w.onclick=()=>void this.plugin.toggleAgent(a.name,!1)}else{let k=u.createEl("button",{cls:"af-btn-sm"});R(k,"play","af-btn-icon"),k.appendText(" Enable"),k.onclick=()=>void this.plugin.toggleAgent(a.name,!0)}let m=u.createEl("button",{cls:"af-btn-sm"});R(m,"edit","af-btn-icon"),m.appendText(" Edit"),m.onclick=()=>this.navigate("edit-agent",a.name);let f=u.createEl("button",{cls:"af-btn-sm danger"});R(f,"trash-2","af-btn-icon"),f.appendText(" Delete"),f.onclick=()=>void this.plugin.deleteAgent(a.name);let g=s.createDiv({cls:"af-detail-tabs"}),y=[{id:"overview",label:"Overview",icon:"layout-dashboard"},{id:"config",label:"Config",icon:"settings"},{id:"runs",label:"Runs",icon:"scroll-text"},{id:"memory",label:"Memory",icon:"file-text"}];for(let k of y){let w=g.createEl("button",{cls:`af-detail-tab${this.agentDetailTab===k.id?" active":""}`});R(w,k.icon,"af-tab-icon"),w.appendText(` ${k.label}`),w.onclick=()=>{this.agentDetailTab=k.id,this.render()}}let v=s.createDiv({cls:"af-detail-tab-content"});switch(this.agentDetailTab){case"overview":this.renderAgentOverviewTab(v,a,o);break;case"config":this.renderAgentConfigTab(v,a);break;case"runs":this.renderAgentRunsTab(v,o);break;case"memory":this.renderAgentMemoryTab(v,a);break}}renderAgentOverviewTab(e,s,n){let a=e.createDiv({cls:"af-dash-grid"}),i=n.length,o=n.filter(w=>w.status==="success").length,c=i>0?Math.round(o/i*100):0,l=i>0?Math.round(n.reduce((w,S)=>w+S.durationSeconds,0)/i):0,h=this.plugin.runtime.getUsageRecords().filter(w=>w.agent===s.name),{tokens:d,cost:u}=this.combinedTotals(n,h),p=u>0?` \xB7 $${u.toFixed(2)}`:"";if(this.renderStatCard(a,"Total Runs",String(i),"","activity","all time"),this.renderStatCard(a,"Success Rate",`${c}%`,"","check-circle-2",`${o}/${i}`),this.renderStatCard(a,"Avg Time",`${l}s`,"","clock","per run"),this.renderStatCard(a,"Total Tokens",Ka(d),"","zap",`all time${p}`),s.isFolder&&(s.heartbeatBody.trim()||s.heartbeatEnabled)){let w=e.createDiv({cls:"af-section-card"}),S=w.createDiv({cls:"af-section-header"}),T=S.createDiv({cls:"af-section-title"});R(T,"heart-pulse"),T.appendText(" Heartbeat");let D=S.createDiv({cls:"af-detail-header-actions"}).createDiv({cls:`af-agent-card-toggle${s.heartbeatEnabled?" on":""}`});D.onclick=async()=>{let E=D.hasClass("on");await this.plugin.repository.updateHeartbeat(s.name,{enabled:!E}),await this.plugin.refreshFromVault(),new b.Notice(`Heartbeat ${E?"paused":"enabled"} for ${s.name}`)};let O=w.createDiv({cls:"af-config-form"});this.renderConfigRow(O,"Schedule",xh(s.heartbeatSchedule));let C=this.plugin.runtime.getNextHeartbeat(s.name);C&&s.heartbeatEnabled&&this.renderConfigRow(O,"Next run",this.timeUntil(C)),s.heartbeatChannel&&this.renderConfigRow(O,"Channel",s.heartbeatChannel)}if(s.skills.length>0){let w=e.createDiv({cls:"af-section-card"}),T=w.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(T,"puzzle"),T.appendText(" Skills");let _=w.createDiv({cls:"af-detail-skills-list"});for(let D of s.skills)_.createSpan({cls:"af-skill-tag",text:D})}let m=s.mcpServers??[];if(m.length>0){let w=e.createDiv({cls:"af-section-card"}),T=w.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(T,"plug"),T.appendText(" MCP Servers");let _=w.createDiv({cls:"af-mcp-overview-list"}),D=this.plugin.repository.getMcpServers();for(let O of m){let C=D.find(M=>M.name===O),E=_.createDiv({cls:"af-mcp-overview-row"}),P=E.createSpan({cls:`af-mcp-status-dot ${C?C.enabled?C.status:"disabled":"disconnected"}`});P.title=C?C.enabled?C.status:"disabled":"unknown",E.createSpan({cls:"af-mcp-overview-name",text:O});let N=C?.toolDetails.length??C?.tools.length??0;N>0?E.createSpan({cls:"af-mcp-overview-tools",text:`${N} tools`}):C&&!C.enabled?E.createSpan({cls:"af-mcp-overview-tools af-muted",text:"disabled"}):C?.status==="needs-auth"&&E.createSpan({cls:"af-mcp-overview-tools af-muted",text:"needs auth"})}}if(s.permissionRules.allow.length>0||s.permissionRules.deny.length>0||s.permissionMode&&s.permissionMode!=="default"){let w=e.createDiv({cls:"af-section-card"}),T=w.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(T,"shield-check"),T.appendText(" Permissions");let _=w.createDiv({cls:"af-config-form"});this.renderConfigRow(_,"Mode",s.permissionMode||"default"),s.permissionRules.allow.length>0&&this.renderConfigRow(_,"Allowed",s.permissionRules.allow.join(", ")),s.permissionRules.deny.length>0&&this.renderConfigRow(_,"Denied",s.permissionRules.deny.join(", "))}let g=e.createDiv({cls:"af-section-card"}),v=g.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(v,"scroll-text"),v.appendText(" Recent Runs");let k=g.createDiv({cls:"af-timeline"});if(n.length===0)this.renderEmptyState(k,"scroll-text","No runs yet","");else for(let w of n.slice(0,5))this.renderTimelineItem(k,w)}renderAgentConfigTab(e,s){let n=e.createDiv({cls:"af-config-form"});this.renderConfigRow(n,"Name",s.name),this.renderConfigRow(n,"Description",s.description??""),this.renderConfigRow(n,"Model",s.model),this.renderConfigRow(n,"Timeout",`${s.timeout}s`),this.renderConfigRow(n,"Working Directory",s.cwd??"(vault root)"),this.renderConfigRow(n,"Permission Mode",s.permissionMode||"default"),this.renderConfigRow(n,"Approval Required",s.approvalRequired.join(", ")||"none"),s.permissionRules.allow.length>0&&this.renderConfigRow(n,"Allowed Commands",s.permissionRules.allow.join(", ")),s.permissionRules.deny.length>0&&this.renderConfigRow(n,"Blocked Commands",s.permissionRules.deny.join(", ")),this.renderConfigRow(n,"Memory",s.memory?"Enabled":"Disabled"),this.renderConfigRow(n,"Auto-compact",s.autoCompactThreshold&&s.autoCompactThreshold>0?`at ${s.autoCompactThreshold}% context`:"disabled"),s.wikiReferences&&s.wikiReferences.length>0&&this.renderConfigRow(n,"Wiki access",s.wikiReferences.map(c=>c.agent).join(", ")),this.renderConfigRow(n,"Tags",s.tags.join(", ")||"none");let a=n.createDiv({cls:"af-config-prompt-section"});if(a.createDiv({cls:"af-slideover-section-title",text:"SYSTEM PROMPT"}),a.createDiv({cls:"af-output-block",text:s.body||"(empty)"}),s.heartbeatBody.trim()){let c=n.createDiv({cls:"af-config-prompt-section"});c.createDiv({cls:"af-slideover-section-title",text:"HEARTBEAT INSTRUCTION"}),c.createDiv({cls:"af-output-block",text:s.heartbeatBody})}let o=n.createDiv({cls:"af-slideover-actions"}).createEl("button",{cls:"af-btn-sm primary"});R(o,"edit","af-btn-icon"),o.appendText(" Edit Agent"),o.onclick=()=>this.navigate("edit-agent",s.name)}renderConfigRow(e,s,n){let a=e.createDiv({cls:"af-detail-row"});a.createSpan({cls:"af-detail-label",text:s}),a.createSpan({cls:"af-detail-value af-mono",text:n})}renderAgentRunsTab(e,s){if(s.length===0){this.renderEmptyState(e,"scroll-text","No runs yet","Run this agent to see history");return}for(let n of s){let a=e.createDiv({cls:"af-run-list-item"}),i=a.createDiv({cls:`af-tl-icon ${this.statusToTimelineClass(n.status)}`});(0,b.setIcon)(i,this.statusToIconName(n.status));let o=a.createDiv({cls:"af-tl-body"}),c=o.createDiv({cls:"af-tl-title"});c.createSpan({text:n.task}),c.createSpan({cls:`af-status-badge ${this.statusToBadgeClass(n.status)}`,text:this.statusToBadgeText(n.status)});let l=o.createDiv({cls:"af-tl-meta"});l.createSpan({text:`${this.formatStarted(n.started)} \xB7 ${this.formatDuration(n.durationSeconds)}`}),n.tokensUsed&&l.createSpan({text:`${n.tokensUsed.toLocaleString()} tokens`}),o.createDiv({cls:"af-tl-desc",text:Wt(n.output,120)}),a.onclick=()=>this.openSlideover(n)}}async renderAgentMemoryTab(e,s){if(!s.memory){this.renderEmptyState(e,"file-text","Memory disabled","Enable memory in agent config");return}let n=await this.plugin.repository.readWorkingMemory(s.name),a=e.createDiv({cls:"af-form-help"}),i=n?.tokenEstimate??0,o=s.reflection.enabled?`reflection on (${s.reflection.schedule})`:"reflection off";a.setText(`~${i} / ${s.memoryTokenBudget} tokens \xB7 ${o}`),!n||n.sections.length===0?this.renderEmptyState(e,"file-text","No memories yet","Agent will learn from runs"):e.createDiv({cls:"af-output-block"}).setText(Ke(n.sections));let c=e.createDiv({cls:"af-slideover-actions"}),l=c.createEl("button",{cls:"af-btn-sm"});R(l,"moon","af-btn-icon"),l.appendText(" Reflect now"),l.onclick=async()=>{l.disabled=!0,l.setText(" Reflecting\u2026");let d=await this.plugin.runtime.runReflectionNow(s.name);new b.Notice(`Agent Fleet: ${d.message}`),await this.renderAgentMemoryTab((e.empty(),e),s)};let h=c.createEl("button",{cls:"af-btn-sm"});R(h,"external-link","af-btn-icon"),h.appendText(" Open in Editor"),h.onclick=()=>void this.plugin.openPath(this.plugin.repository.getWorkingMemoryPath(s.name))}timeAgo(e){let s=Math.round((Date.now()-e.getTime())/1e3);if(s<60)return"just now";let n=Math.round(s/60);if(n<60)return`${n}m ago`;let a=Math.round(n/60);return a<24?`${a}h ago`:`${Math.round(a/24)}d ago`}timeUntil(e){let s=Math.round((e.getTime()-Date.now())/1e3);if(s<60)return"< 1m";let n=Math.round(s/60);if(n<60)return`in ${n}m`;let a=Math.round(n/60);return a<24?`in ${a}h`:`in ${Math.round(a/24)}d`}renderKanbanPage(e){let s=e.createDiv({cls:"af-kanban-page"}),n=this.plugin.runtime.getSnapshot(),a=this.plugin.runtime.getRecentRuns(),i=s.createDiv({cls:"af-kanban-toolbar"});i.createDiv({cls:"af-page-title",text:"Tasks Board"}),i.createDiv({cls:"af-toolbar-spacer"});let o=i.createEl("button",{cls:"af-btn-sm primary"});R(o,"plus","af-btn-icon"),o.appendText(" New Task"),o.onclick=()=>this.navigate("create-task");let c=s.createDiv({cls:"af-kanban-board"}),l=[],h=[],d=[],u=[],p=[],m=new Set;for(let v of n.agents){let k=this.plugin.runtime.getAgentState(v.name);k.status==="running"&&k.currentTaskId&&m.add(k.currentTaskId)}let f=this.toLocalDateStr(new Date);for(let v of a)v.status==="success"&&this.runToLocalDate(v.started)===f?u.push(v):(v.status==="failure"||v.status==="timeout"||v.status==="cancelled")&&this.runToLocalDate(v.started)===f&&p.push(v);let g=new Set(u.map(v=>v.task)),y=new Set(p.map(v=>v.task));for(let v of n.tasks){let k=g.has(v.taskId)||y.has(v.taskId)||v.lastRun&&this.runToLocalDate(v.lastRun)===f;if(m.has(v.taskId))d.push(v);else{if(k&&!v.schedule)continue;v.schedule&&v.enabled?h.push(v):l.push(v)}}this.renderKanbanColumn(c,"Backlog","inbox",l.length,v=>{for(let k of l)this.renderKanbanTaskCard(v,k,n,!0)},"backlog"),this.renderKanbanColumn(c,"Scheduled","clock",h.length,v=>{for(let k of h)this.renderKanbanTaskCard(v,k,n,!0)},"scheduled"),this.renderKanbanColumn(c,"Running","loader-2",d.length,v=>{for(let k of d)this.renderKanbanRunningCard(v,k)},"running",!1,"running"),this.renderKanbanColumn(c,"Done","check-circle-2",u.length,v=>{for(let k of u.slice(0,10))this.renderKanbanCompletedCard(v,k)},"completed"),this.renderKanbanColumn(c,"Failed","x-circle",p.length,v=>{for(let k of p)this.renderKanbanFailedCard(v,k)},"failed",!1,"failed")}renderKanbanColumn(e,s,n,a,i,o,c=!1,l){let h=e.createDiv({cls:`af-kanban-column${l?` af-kanban-${l}`:""}`});(o==="backlog"||o==="scheduled")&&Yo(h,m=>this.handleTaskDrop(m,o));let u=h.createDiv({cls:"af-kanban-col-header"}).createDiv({cls:"af-kanban-col-title"});R(u,n),u.appendText(` ${s} `),u.createSpan({cls:"af-kanban-col-count",text:String(a)});let p=h.createDiv({cls:"af-kanban-col-body"});if(i(p),a===0&&p.createDiv({cls:"af-kanban-empty",text:"No items"}),c){let f=h.createDiv({cls:"af-kanban-col-add"}).createEl("button");R(f,"plus","af-btn-icon"),f.appendText(" Add task"),f.onclick=()=>{this.navigate("create-task")}}}handleTaskDrop(e,s){let n=this.plugin.runtime.getSnapshot().tasks.find(a=>a.taskId===e);if(n){if(s==="backlog")this.setTaskEnabled(n,!1).then(()=>{new b.Notice(`Task "${e}" moved to backlog (disabled)`)});else if(s==="scheduled"){if(!n.schedule&&!n.runAt){new b.Notice(`Task "${e}" needs a schedule. Open task details to set one.`),this.navigate("task-detail",e);return}this.setTaskEnabled(n,!0).then(()=>{new b.Notice(`Task "${e}" moved to scheduled (enabled)`)})}}}async setTaskEnabled(e,s){let n=this.plugin.app.vault.getAbstractFileByPath(e.filePath);if(!n||!(n instanceof b.TFile))return;let a=await this.plugin.app.vault.cachedRead(n),{frontmatter:i,body:o}=J(a);i.enabled=s,await this.plugin.app.vault.modify(n,H(i,o)),await this.plugin.refreshFromVault()}renderKanbanTaskCard(e,s,n,a){let i=e.createDiv({cls:`af-kanban-card af-priority-${s.priority}`});if(a){Vo(i,s.taskId);let f=i.createDiv({cls:"af-kanban-card-grip"});(0,b.setIcon)(f,"grip-vertical")}let o=i.createDiv({cls:"af-kanban-card-header"});o.createDiv({cls:"af-kanban-card-title",text:s.taskId});let l=(n.agents.find(f=>f.name===s.agent)?.enabled??!1)&&s.enabled,h=o.createSpan({cls:`af-kanban-card-status ${l?"active":"inactive"}`});h.title=l?"Active":"Inactive";let d=i.createDiv({cls:"af-kanban-card-agent"}),u=d.createSpan({cls:"af-kanban-card-agent-icon"});(0,b.setIcon)(u,"bot"),d.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let m=i.createDiv({cls:"af-kanban-card-footer"}).createSpan({cls:"af-kanban-card-schedule"});l?s.schedule?(R(m,"refresh-cw","af-meta-icon"),m.appendText(` ${this.humanizeCron(s.schedule)}`)):m.appendText(s.runAt??"Manual"):(R(m,"pause","af-meta-icon"),m.appendText(" Paused")),i.onclick=()=>this.navigate("task-detail",s.taskId)}renderKanbanRunningCard(e,s){let n=e.createDiv({cls:"af-kanban-card af-kanban-card-running"});n.createDiv({cls:"af-kanban-card-title",text:s.taskId});let a=n.createDiv({cls:"af-kanban-card-agent"}),i=a.createSpan({cls:"af-kanban-card-agent-icon"});(0,b.setIcon)(i,"bot"),a.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let c=this.plugin.runtime.getSnapshot().agents.find(S=>S.name===s.agent)?.timeout??300,l=this.plugin.runtime.getAgentState(s.agent),h=l.runStarted?new Date(l.runStarted).getTime():Date.now(),p=n.createDiv({cls:"af-kanban-progress"}).createDiv({cls:"af-kanban-progress-track"}).createDiv({cls:"af-kanban-progress-bar af-kanban-progress-bar-real"}),m=(Date.now()-h)/1e3,f=Math.min(95,m/c*100);p.setCssStyles({width:`${f}%`});let g=n.createDiv({cls:"af-kanban-card-footer"}),y=g.createSpan({cls:"af-kanban-card-schedule"});R(y,"loader-2","af-meta-icon");let v=Math.round(m);y.appendText(` ${v}s / ${c}s`);let k=g.createEl("button",{cls:"af-kanban-stop-btn"});(0,b.setIcon)(k,"square"),k.title="Stop task",k.onclick=S=>{S.stopPropagation(),this.plugin.runtime.abortAgentRun(s.agent),new b.Notice(`Stopped task "${s.taskId}"`)};let w=window.setInterval(()=>{let S=(Date.now()-h)/1e3,T=Math.min(95,S/c*100);p.setCssStyles({width:`${T}%`});let _=Math.round(S);y.textContent="",(0,b.setIcon)(y,"loader-2"),y.appendText(` ${_}s / ${c}s`)},1e3);this.streamingUnsubscribes.push(()=>window.clearInterval(w))}renderKanbanCompletedCard(e,s){let n=e.createDiv({cls:"af-kanban-card"});n.createDiv({cls:"af-kanban-card-title",text:s.task});let a=n.createDiv({cls:"af-kanban-card-agent"}),i=a.createSpan({cls:"af-kanban-card-agent-icon"});(0,b.setIcon)(i,"bot"),a.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let c=n.createDiv({cls:"af-kanban-card-footer"}).createSpan({cls:"af-kanban-card-schedule"});R(c,"check-circle-2","af-meta-icon"),c.appendText(` ${this.formatStarted(s.started)} \xB7 ${this.formatDuration(s.durationSeconds)}`),n.onclick=()=>this.openSlideover(s)}renderKanbanFailedCard(e,s){let n=s.status==="cancelled",a=e.createDiv({cls:`af-kanban-card ${n?"af-kanban-card-cancelled":"af-kanban-card-failed"}`});a.createDiv({cls:"af-kanban-card-title",text:s.task});let i=a.createDiv({cls:"af-kanban-card-agent"}),o=i.createSpan({cls:"af-kanban-card-agent-icon"});(0,b.setIcon)(o,"bot"),i.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let c=n?`Stopped after ${s.durationSeconds}s`:s.status==="timeout"?`Timeout after ${s.durationSeconds}s`:Wt(s.output,60),l=a.createDiv({cls:"af-kanban-card-error"});R(l,n?"square":"alert-triangle","af-meta-icon"),l.appendText(` ${c}`);let h=a.createDiv({cls:"af-kanban-card-footer"}),d=h.createSpan({cls:"af-kanban-card-schedule"});if(R(d,n?"square":"x-circle","af-meta-icon"),d.appendText(` ${this.formatStarted(s.started)}`),!n){let u=h.createEl("button",{cls:"af-btn-sm"});R(u,"refresh-cw","af-btn-icon"),u.appendText(" Retry"),u.onclick=p=>{p.stopPropagation(),this.plugin.runAgentPrompt(s.agent)}}a.onclick=()=>this.openSlideover(s)}renderRunsPage(e){let s=e.createDiv({cls:"af-runs-page"}),n=this.plugin.runtime.getRecentRuns(),a=s.createDiv({cls:"af-runs-toolbar"});a.createDiv({cls:"af-page-title",text:"Run History"}),a.createDiv({cls:"af-toolbar-spacer"});let i=s.createDiv({cls:"af-runs-table"});if(n.length===0){this.renderEmptyState(i,"scroll-text","No runs yet","Run an agent to see history here");return}let o=i.createEl("table"),l=o.createEl("thead").createEl("tr");for(let d of["Status","Agent","Task","Started","Duration","Tokens","Model"])l.createEl("th",{text:d});let h=o.createEl("tbody");for(let d of n.slice(0,50))this.renderRunRow(h,d)}renderRunRow(e,s){let n=e.createEl("tr"),i=n.createEl("td").createSpan({cls:`af-status-badge ${this.statusToBadgeClass(s.status)}`}),o=i.createSpan();(0,b.setIcon)(o,this.statusToIconName(s.status)),i.appendText(` ${this.statusToBadgeText(s.status)}`);let c=n.createEl("td",{cls:"af-agent-link"});c.setText(s.agent),c.onclick=l=>{l.stopPropagation(),this.navigate("agent-detail",s.agent)},n.createEl("td",{text:s.task}),n.createEl("td",{cls:"af-mono",text:this.formatStarted(s.started)}),n.createEl("td",{cls:"af-mono",text:this.formatDuration(s.durationSeconds)}),n.createEl("td",{cls:"af-mono",text:s.tokensUsed?s.tokensUsed.toLocaleString():"\u2014"}),n.createEl("td",{cls:"af-mono",text:s.model}),n.setCssStyles({cursor:"pointer"}),n.onclick=()=>this.openSlideover(s)}renderSkillsPage(e){let s=e.createDiv({cls:"af-skills-page"}),n=this.plugin.runtime.getSnapshot(),a=s.createDiv({cls:"af-agents-toolbar"});a.createDiv({cls:"af-page-title",text:"Skills Library"}),a.createDiv({cls:"af-toolbar-spacer"});let i=a.createEl("button",{cls:"af-btn-sm primary"});R(i,"plus","af-btn-icon"),i.appendText(" New Skill"),i.onclick=()=>void this.plugin.createSkillTemplate();let o=s.createDiv({cls:"af-skills-grid"});if(n.skills.length===0){this.renderEmptyState(o,"puzzle","No skills yet","Create skills to give agents specialized abilities");return}for(let c of n.skills)this.renderSkillCard(o,c,n.agents)}renderSkillCard(e,s,n){let a=e.createDiv({cls:"af-skill-card"}),i=a.createDiv({cls:"af-skill-card-header"}),o=i.createDiv({cls:"af-skill-card-icon"});(0,b.setIcon)(o,this.getSkillIcon(s.name));let c=i.createEl("button",{cls:"af-btn-sm af-btn-xs"});R(c,"edit","af-btn-icon"),c.onclick=h=>{h.stopPropagation(),this.navigate("edit-skill",s.name)},a.createDiv({cls:"af-skill-card-name",text:s.name}),a.createDiv({cls:"af-skill-card-desc",text:s.description??"No description"});let l=n.filter(h=>h.skills.includes(s.name));if(l.length>0){let h=a.createDiv({cls:"af-skill-card-agents"});for(let d of l)h.createSpan({cls:"af-skill-card-agent-tag",text:d.name})}}renderChannelsPage(e){let s=e.createDiv({cls:"af-agents-page"}),n=this.plugin.runtime.getSnapshot(),a=s.createDiv({cls:"af-agents-toolbar"});a.createDiv({cls:"af-page-title",text:"Channels"}),a.createDiv({cls:"af-toolbar-spacer"});let i=a.createEl("button",{cls:"af-btn-sm primary"});R(i,"plus","af-btn-icon"),i.appendText(" New Channel"),i.onclick=()=>this.navigate("create-channel");let o=s.createDiv({cls:"af-agents-grid"});if(n.channels.length===0){this.renderEmptyState(o,"radio","No channels configured","Connect an agent to Slack or another chat platform");return}for(let c of n.channels)this.renderChannelCard(o,c,n.validationIssues)}async renderWikiKeepersPage(e){let s=e.createDiv({cls:"af-agents-page"}),n=this.plugin.runtime.getSnapshot(),a=s.createDiv({cls:"af-agents-toolbar"});a.createDiv({cls:"af-page-title",text:"Wiki Keepers"}),a.createDiv({cls:"af-toolbar-spacer"});let i=n.agents.filter(c=>c.wikiKeeper!==void 0);if(i.length===0){this.renderEmptyState(s,"library","No Wiki Keepers yet","Open Settings \u2192 Agent Fleet \u2192 Wiki Keepers \u2192 + Add to create one.");return}let o=s.createDiv({cls:"af-wk-list"});o.setCssStyles({display:"flex"}),o.setCssStyles({flexDirection:"column"}),o.setCssStyles({gap:"16px"});for(let c of i)await this.renderWikiKeeperCard(o,c)}async renderWikiKeeperCard(e,s){let n=s.wikiKeeper,a=e.createDiv({cls:"af-card"});a.setCssStyles({padding:"16px"}),a.setCssStyles({border:"1px solid var(--background-modifier-border)"}),a.setCssStyles({borderRadius:"8px"});let i=a.createDiv();i.setCssStyles({display:"flex"}),i.setCssStyles({alignItems:"center"}),i.setCssStyles({gap:"12px"}),i.setCssStyles({marginBottom:"12px"});let o=i.createDiv();o.setCssStyles({flex:"1"}),o.createEl("strong",{text:s.name});let c=n.scopeRoot||"(whole vault)";o.createEl("div",{text:`Scope: ${c} \xB7 topics: ${n.topicsRoot}/ \xB7 log: ${n.logPath}`,cls:"af-form-hint"});let l=i.createEl("button",{cls:"af-btn-sm"});l.appendText("Open log"),l.onclick=()=>{let g=n.scopeRoot?`${n.scopeRoot}/${n.logPath}`:n.logPath,y=this.plugin.app.vault.getAbstractFileByPath(g);y instanceof b.TFile?this.plugin.app.workspace.getLeaf().openFile(y):new b.Notice(`Log file not found: ${g}`)};let h=n.scopeRoot?`${n.scopeRoot}/${n.logPath}`:n.logPath,d=this.plugin.app.vault.getAbstractFileByPath(h),u=null;if(d instanceof b.TFile)try{let g=await this.plugin.app.vault.cachedRead(d);u=Ko(g)}catch{u=null}if(!u){a.createDiv({cls:"af-form-hint"}).setText("No lint report yet. Run wiki-lint manually or wait for the weekly task to fire.");return}let p=a.createDiv();if(p.setCssStyles({display:"flex"}),p.setCssStyles({alignItems:"baseline"}),p.setCssStyles({gap:"12px"}),p.setCssStyles({marginBottom:"8px"}),p.createEl("strong",{text:`Lint ${u.date}`}),p.createSpan({cls:"af-form-hint",text:`${u.summary.length} summary lines \xB7 ${u.autoApplied.length} auto-applied \xB7 ${u.needsReview.length} needs review`}),u.summary.length>0){let g=a.createEl("details");g.createEl("summary",{text:"Summary"});let y=g.createEl("ul");y.setCssStyles({marginTop:"4px"});for(let v of u.summary)y.createEl("li",{text:v})}if(u.autoApplied.length>0){let g=a.createEl("details");g.createEl("summary",{text:`Auto-applied (${u.autoApplied.length})`});let y=g.createEl("ul");y.setCssStyles({marginTop:"4px"});for(let v of u.autoApplied)y.createEl("li",{text:v})}if(u.refreshChained.length>0){let g=a.createEl("details");g.createEl("summary",{text:`Refresh chained (${u.refreshChained.length})`});let y=g.createEl("ul");y.setCssStyles({marginTop:"4px"});for(let v of u.refreshChained)y.createEl("li",{text:v})}let m=a.createDiv();if(m.setCssStyles({marginTop:"12px"}),m.createEl("strong",{text:`Needs review (${u.needsReview.length})`}),u.needsReview.length===0){m.createDiv({cls:"af-form-hint",text:"All clear. Nothing requires manual review from this lint pass."});return}let f=m.createDiv();f.setCssStyles({display:"flex"}),f.setCssStyles({flexDirection:"column"}),f.setCssStyles({gap:"6px"}),f.setCssStyles({marginTop:"8px"});for(let g of u.needsReview){let y=f.createDiv();y.setCssStyles({display:"flex"}),y.setCssStyles({alignItems:"flex-start"}),y.setCssStyles({gap:"8px"}),y.setCssStyles({padding:"8px 10px"}),y.setCssStyles({background:"var(--background-secondary)"}),y.setCssStyles({borderRadius:"4px"}),y.setCssStyles({fontSize:"13px"});let v=y.createDiv();v.setCssStyles({flex:"1"}),v.setText(g);let k=y.createEl("button",{cls:"af-btn-sm",text:"Dismiss"});k.title="Hide this item from the dashboard until the next lint pass (does not modify log.md).",k.onclick=()=>{y.remove()}}}renderChannelCard(e,s,n){let a=this.plugin.channelManager?.getChannelStatus(s.name)??"disabled",i=Qo(a),o=s.enabled&&a!=="disabled"?"af-agent-card":"af-agent-card disabled",c=e.createDiv({cls:o});c.setCssStyles({cursor:"default"});let l=c.createDiv({cls:"af-agent-card-header"}),h=l.createDiv({cls:`af-agent-card-avatar ${i}`});(0,b.setIcon)(h,"radio");let d=l.createDiv({cls:"af-agent-card-titleblock"});d.createDiv({cls:"af-agent-card-name",text:s.name}),d.createDiv({cls:"af-agent-card-desc",text:`Default: ${s.defaultAgent}`});let u=l.createSpan({cls:`af-pill ${Sh(a)}`});if(u.createSpan({cls:"af-dot"}),u.appendText(` ${a}`),s.allowedAgents.length>0){let T=c.createDiv({cls:"af-agent-card-skills"});for(let _ of s.allowedAgents){let D=T.createSpan({cls:"af-skill-tag",text:_});_===s.defaultAgent&&D.setCssStyles({fontWeight:"700"})}}let p=c.createDiv({cls:"af-agent-card-stats"}),m=this.plugin.channelManager?.getSessionCount(s.name)??0,f=this.plugin.channelManager?.getMetrics(s.name),g=s.allowedAgents.length>0?String(s.allowedAgents.length):"all";this.renderAgentStat(p,g,"Agents"),this.renderAgentStat(p,String(m),"Sessions"),this.renderAgentStat(p,String(f?.messagesReceived??0),"In"),this.renderAgentStat(p,String(f?.messagesSent??0),"Out");let y=c.createDiv({cls:"af-agent-card-footer"}),v=[s.type];s.enabled||v.push("disabled"),s.allowedUsers.length>0?v.push(`${s.allowedUsers.length} user(s)`):v.push("allowlist empty"),y.createSpan({cls:"af-agent-card-meta",text:v.join(" \xB7 ")});let w=y.createDiv({cls:"af-agent-card-actions"}).createEl("button",{cls:"af-btn-sm"});R(w,"edit","af-btn-icon"),w.appendText(" Edit"),w.onclick=T=>{T.stopPropagation(),this.navigate("edit-channel",s.name)};let S=n.filter(T=>T.path===s.filePath);if(S.length>0){let T=c.createDiv({cls:"af-channel-issues"});for(let _ of S)T.createDiv({cls:"af-channel-issue-row",text:_.message})}}renderCreateChannelPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=this.plugin.runtime.getSnapshot(),a=this.plugin.channelCredentials.list(),i=s.createDiv({cls:"af-detail-header"}),o=i.createDiv({cls:"af-detail-header-left"}),c=o.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(c,"plus");let l=o.createDiv();l.createDiv({cls:"af-detail-header-name",text:"Create New Channel"}),l.createDiv({cls:"af-detail-header-desc",text:"Connect an external chat transport to an agent"});let h=i.createDiv({cls:"af-detail-header-actions"}),d={name:"",type:"slack",defaultAgent:n.agents[0]?.name??"",allowedAgents:[],credentialRef:a[0]?.ref??"",allowedUsers:"",perUserSessions:!0,channelContext:"",enabled:!0,tags:"",body:"",transportJson:""},u=s.createDiv({cls:"af-create-form"}),p=u.createDiv({cls:"af-create-section"}),m=p.createDiv({cls:"af-create-section-header"}),f=m.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(f,"radio"),m.createSpan({text:"Channel Details"}),this.createFormField(p,"Name","my-slack","Unique identifier for this channel",j=>{d.name=j});let g=p.createDiv({cls:"af-form-row"});g.createDiv({cls:"af-form-label",text:"Type"});let y=g.createEl("select",{cls:"af-form-select"});y.createEl("option",{text:"slack",attr:{value:"slack"}}),y.createEl("option",{text:"telegram",attr:{value:"telegram"}}),y.createEl("option",{text:"discord",attr:{value:"discord"}}),y.addEventListener("change",()=>{d.type=y.value});let v=p.createDiv({cls:"af-form-row"}),k=v.createDiv({cls:"af-form-label"});k.setText("Credential"),this.addTooltip(k,"Configured in Settings \u2192 Agent Fleet \u2192 Channel Credentials");let w=v.createEl("select",{cls:"af-form-select"});a.length===0&&w.createEl("option",{text:"(no credentials configured)",attr:{value:""}});for(let j of a)w.createEl("option",{text:`${j.ref} (${j.entry.type})`,attr:{value:j.ref}});w.addEventListener("change",()=>{d.credentialRef=w.value});let S=p.createDiv({cls:"af-form-row af-form-row-toggle"});S.createDiv({cls:"af-form-label",text:"Enabled"});let T=S.createDiv({cls:"af-agent-card-toggle on"});T.onclick=()=>{let j=T.hasClass("on");T.toggleClass("on",!j),d.enabled=!j};let _=u.createDiv({cls:"af-create-section"}),D=_.createDiv({cls:"af-create-section-header"}),O=D.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(O,"bot"),D.createSpan({text:"Agent Routing"});let C=_.createDiv({cls:"af-form-row"}),E=C.createDiv({cls:"af-form-label"});E.setText("Default agent"),this.addTooltip(E,"Used when no @agent-name prefix is given in a message");let P=C.createEl("select",{cls:"af-form-select"});for(let j of n.agents)P.createEl("option",{text:j.name,attr:{value:j.name}});P.addEventListener("change",()=>{d.defaultAgent=P.value});let N=_.createDiv({cls:"af-form-row"}),M=N.createDiv({cls:"af-form-label"});M.setText("Allowed agents"),this.addTooltip(M,"Agents reachable via @prefix. Leave unchecked to allow all agents.");let U=N.createDiv({cls:"af-form-checkboxes"});for(let j of n.agents){let Ce=U.createEl("label",{cls:"af-form-checkbox-label"}),xe=Ce.createEl("input",{attr:{type:"checkbox",value:j.name}});Ce.appendText(` ${j.name}`),xe.addEventListener("change",()=>{xe.checked?d.allowedAgents.includes(j.name)||d.allowedAgents.push(j.name):d.allowedAgents=d.allowedAgents.filter(he=>he!==j.name)})}let $=_.createDiv({cls:"af-form-row af-form-row-toggle"}),Z=$.createDiv({cls:"af-form-label"});Z.setText("Per-user sessions"),this.addTooltip(Z,"Each external user gets their own isolated Claude session");let de=$.createDiv({cls:"af-agent-card-toggle on"});de.onclick=()=>{let j=de.hasClass("on");de.toggleClass("on",!j),d.perUserSessions=!j};let me=u.createDiv({cls:"af-create-section"}),ge=me.createDiv({cls:"af-create-section-header"}),X=ge.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(X,"shield-check"),ge.createSpan({text:"Access Control"});let W=me.createDiv({cls:"af-form-label"});W.setText("Allowed users"),this.addTooltip(W,"User IDs, one per line \u2014 Slack (U...), Telegram (numeric), or Discord (numeric snowflakes). Only listed users can reach the bot.");let K=me.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`U0AQW6P37N1
|
|
11951
|
-
U0BXYZ12345`,rows:"4"}});K.addEventListener("input",()=>{d.allowedUsers=K.value});let ne=u.createDiv({cls:"af-create-section"}),G=ne.createDiv({cls:"af-create-section-header"}),ee=G.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(ee,"message-square");let Q=G.createSpan({text:"Channel Context"});this.addTooltip(Q,"Extra instructions appended to the agent's system prompt when reached through this channel");let ae=ne.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"You are being contacted via Slack. Keep replies concise...",rows:"6"}});ae.addEventListener("input",()=>{d.channelContext=ae.value}),this.createFormField(p,"Tags","ops, internal","Comma-separated metadata",j=>{d.tags=j});let ve=u.createDiv({cls:"af-create-section"}),Pe=ve.createDiv({cls:"af-create-section-header"}),Ie=Pe.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ie,"settings");let Me=Pe.createSpan({text:"Advanced"});this.addTooltip(Me,"Markdown body (shown in the channel detail page) and transport-specific overrides");let Fe=ve.createDiv({cls:"af-form-label"});Fe.setText("Body (markdown)"),this.addTooltip(Fe,"Free-form notes for this channel. Shown in the channel detail page; not sent to the agent.");let ke=ve.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Notes, runbook snippets, escalation contacts\u2026",rows:"4"}});ke.addEventListener("input",()=>{d.body=ke.value});let Oe=ve.createDiv({cls:"af-form-label"});Oe.setText("Transport config (JSON)"),this.addTooltip(Oe,"Optional JSON object for transport-specific overrides (e.g. Slack socket_mode, telegram webhook settings). Leave blank for defaults.");let Ue=ve.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`{
|
|
11952
|
-
"socket_mode": true
|
|
11953
|
-
}`,rows:"4"}});Ue.addEventListener("input",()=>{d.transportJson=Ue.value});let Ne=s.createDiv({cls:"af-create-footer"}),q=Ne.createEl("button",{cls:"af-btn-sm",text:"Cancel"});q.onclick=()=>this.navigate("channels");let re=Ne.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(re,"plus","af-btn-icon"),re.appendText(" Create Channel"),re.onclick=async()=>{let j=d.name.trim();if(!j){new b.Notice("Channel name is required.");return}if(!d.credentialRef){new b.Notice("Select a credential.");return}let Ce;if(d.transportJson.trim())try{let ie=JSON.parse(d.transportJson);if(ie&&typeof ie=="object"&&!Array.isArray(ie))Ce=ie;else{new b.Notice("Transport config must be a JSON object.");return}}catch(ie){new b.Notice(`Transport JSON is invalid: ${ie instanceof Error?ie.message:String(ie)}`);return}let xe=ie=>ie.split(/[\n,]+/).map(I=>I.trim()).filter(Boolean),he=ie=>ie.split(",").map(I=>I.trim()).filter(Boolean),$e={name:oe(j),type:d.type,default_agent:d.defaultAgent,allowed_agents:d.allowedAgents.length>0?d.allowedAgents:void 0,enabled:d.enabled,credential_ref:d.credentialRef,allowed_users:xe(d.allowedUsers),per_user_sessions:d.perUserSessions,channel_context:d.channelContext.trim()||void 0,tags:he(d.tags).length>0?he(d.tags):void 0,transport:Ce};try{let ie=oe(j),I=await this.plugin.repository.getAvailablePath(this.plugin.repository.getSubfolder("channels"),ie);await this.plugin.app.vault.create(I,H($e,d.body.trim())),new b.Notice(`Channel "${ie}" created.`),await this.plugin.refreshFromVault(),this.navigate("edit-channel",ie)}catch(ie){let I=ie instanceof Error?ie.message:String(ie);new b.Notice(`Failed to create channel: ${I}`)}}}renderEditChannelPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"radio","No channel selected","");return}let a=this.plugin.runtime.getSnapshot().channels.find(I=>I.name===n);if(!a){this.renderEmptyState(s,"radio","Channel not found",`Channel "${n}" was not found`);return}let i=this.plugin.runtime.getSnapshot(),o=this.plugin.channelCredentials.list(),c=this.plugin.channelManager?.getChannelStatus(a.name)??"disabled",l=s.createDiv({cls:"af-detail-header"}),h=l.createDiv({cls:"af-detail-header-left"}),d=h.createDiv({cls:`af-agent-card-avatar ${Qo(c)}`});(0,b.setIcon)(d,"radio");let u=h.createDiv();u.createDiv({cls:"af-detail-header-name",text:`Edit Channel: ${a.name}`}),u.createDiv({cls:"af-detail-header-desc",text:`Status: ${c}`});let p=l.createDiv({cls:"af-detail-header-actions"}),m={type:a.type,defaultAgent:a.defaultAgent,allowedAgents:[...a.allowedAgents],credentialRef:a.credentialRef,allowedUsers:a.allowedUsers.join(`
|
|
11954
|
-
`),perUserSessions:a.perUserSessions,channelContext:a.channelContext,enabled:a.enabled,tags:a.tags.join(", "),body:a.body,transportJson:Object.keys(a.transport).length>0?JSON.stringify(a.transport,null,2):""},f=s.createDiv({cls:"af-create-form"}),g=f.createDiv({cls:"af-create-section"}),y=g.createDiv({cls:"af-create-section-header"}),v=y.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(v,"radio"),y.createSpan({text:"Channel Details"});let k=g.createDiv({cls:"af-form-row"});k.createDiv({cls:"af-form-label",text:"Name"}),k.createEl("input",{cls:"af-form-input",attr:{type:"text",value:a.name,disabled:"true"}}).setCssStyles({opacity:"0.6"});let S=g.createDiv({cls:"af-form-row"});S.createDiv({cls:"af-form-label",text:"Type"});let T=S.createEl("select",{cls:"af-form-select"});for(let I of["slack","telegram","discord"]){let se=T.createEl("option",{text:I,attr:{value:I}});I===a.type&&(se.selected=!0)}T.addEventListener("change",()=>{m.type=T.value});let _=g.createDiv({cls:"af-form-row"}),D=_.createDiv({cls:"af-form-label"});D.setText("Credential"),this.addTooltip(D,"Configured in Settings \u2192 Agent Fleet \u2192 Channel Credentials");let O=_.createEl("select",{cls:"af-form-select"});o.length===0&&O.createEl("option",{text:"(no credentials configured)",attr:{value:""}});for(let I of o){let se=O.createEl("option",{text:`${I.ref} (${I.entry.type})`,attr:{value:I.ref}});I.ref===a.credentialRef&&(se.selected=!0)}O.addEventListener("change",()=>{m.credentialRef=O.value});let C=g.createDiv({cls:"af-form-row af-form-row-toggle"});C.createDiv({cls:"af-form-label",text:"Enabled"});let E=C.createDiv({cls:`af-agent-card-toggle${a.enabled?" on":""}`});E.onclick=()=>{let I=E.hasClass("on");E.toggleClass("on",!I),m.enabled=!I};let P=f.createDiv({cls:"af-create-section"}),N=P.createDiv({cls:"af-create-section-header"}),M=N.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(M,"bot"),N.createSpan({text:"Agent Routing"});let U=P.createDiv({cls:"af-form-row"}),$=U.createDiv({cls:"af-form-label"});$.setText("Default agent"),this.addTooltip($,"Used when no @agent-name prefix is given in a message");let Z=U.createEl("select",{cls:"af-form-select"});for(let I of i.agents){let se=Z.createEl("option",{text:I.name,attr:{value:I.name}});I.name===a.defaultAgent&&(se.selected=!0)}Z.addEventListener("change",()=>{m.defaultAgent=Z.value});let de=P.createDiv({cls:"af-form-row"}),me=de.createDiv({cls:"af-form-label"});me.setText("Allowed agents"),this.addTooltip(me,"Agents reachable via @prefix. Leave unchecked to allow all agents.");let ge=de.createDiv({cls:"af-form-checkboxes"});for(let I of i.agents){let se=ge.createEl("label",{cls:"af-form-checkbox-label"}),ce=se.createEl("input",{attr:{type:"checkbox",value:I.name}});a.allowedAgents.includes(I.name)&&(ce.checked=!0),se.appendText(` ${I.name}`),ce.addEventListener("change",()=>{ce.checked?m.allowedAgents.includes(I.name)||m.allowedAgents.push(I.name):m.allowedAgents=m.allowedAgents.filter(te=>te!==I.name)})}let X=P.createDiv({cls:"af-form-row af-form-row-toggle"}),W=X.createDiv({cls:"af-form-label"});W.setText("Per-user sessions"),this.addTooltip(W,"Each external user gets their own isolated Claude session");let K=X.createDiv({cls:`af-agent-card-toggle${a.perUserSessions?" on":""}`});K.onclick=()=>{let I=K.hasClass("on");K.toggleClass("on",!I),m.perUserSessions=!I};let ne=f.createDiv({cls:"af-create-section"}),G=ne.createDiv({cls:"af-create-section-header"}),ee=G.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(ee,"shield-check"),G.createSpan({text:"Access Control"});let Q=ne.createDiv({cls:"af-form-label"});Q.setText("Allowed users"),this.addTooltip(Q,"Slack user IDs (U...), one per line. Only listed users can reach the bot.");let ae=ne.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`U0AQW6P37N1
|
|
11955
|
-
U0BXYZ12345`,rows:"4"}});ae.value=a.allowedUsers.join(`
|
|
11956
|
-
`),ae.addEventListener("input",()=>{m.allowedUsers=ae.value});let ve=f.createDiv({cls:"af-create-section"}),Pe=ve.createDiv({cls:"af-create-section-header"}),Ie=Pe.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ie,"message-square");let Me=Pe.createSpan({text:"Channel Context"});this.addTooltip(Me,"Extra instructions appended to the agent's system prompt when reached through this channel");let Fe=ve.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"You are being contacted via Slack. Keep replies concise...",rows:"6"}});Fe.value=a.channelContext,Fe.addEventListener("input",()=>{m.channelContext=Fe.value}),this.createFormField(g,"Tags","ops, internal","Comma-separated metadata",I=>{m.tags=I},a.tags.join(", "));let ke=f.createDiv({cls:"af-create-section"}),Oe=ke.createDiv({cls:"af-create-section-header"}),Ue=Oe.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ue,"settings");let Ne=Oe.createSpan({text:"Advanced"});this.addTooltip(Ne,"Markdown body (shown in the channel detail page) and transport-specific overrides"),ke.createDiv({cls:"af-form-label"}).setText("Body (markdown)");let re=ke.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Notes, runbook snippets, escalation contacts\u2026",rows:"4"}});re.value=a.body,re.addEventListener("input",()=>{m.body=re.value});let j=ke.createDiv({cls:"af-form-label"});j.setText("Transport config (JSON)"),this.addTooltip(j,"Optional JSON object for transport-specific overrides (e.g. Slack socket_mode). Leave blank for defaults.");let Ce=ke.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`{
|
|
11939
|
+
`}async getOrCreateSession(e,t,s){let n=`${e.name}:${t}:${s}`,r=this.sessions.get(n);if(r)return r.session;let i=this.deps.getRepository(),o=i.getAgentByName(s);if(!o)throw new Error(`Channel ${e.name} bound to missing agent ${s}`);let l=new ys(o,this.deps.getSettings(),i,this.deps.vault,{channelName:e.name,conversationId:`${t}:${s}`,channelContext:e.channelContext||void 0,mcpAuth:this.deps.getMcpAuth?.()});this.deps.recordUsage&&l.setUsageRecorder(this.deps.recordUsage);try{await l.loadPersistedState()}catch{}return this.sessions.set(n,{session:l,channelName:e.name,conversationId:t,sessionKey:n}),l}resolveAllowedAgents(e){let t=new Set(this.deps.getRepository().getSnapshot().agents.filter(n=>n.enabled).map(n=>n.name));return(e.allowedAgents.length>0?e.allowedAgents:[...t]).filter(n=>t.has(n))}async persistBindings(e){let t=`${e}:`,s={};for(let[o,l]of this.threadBindings)o.startsWith(t)&&(s[o.slice(t.length)]=l);let n=this.deps.getSettings(),r=(0,xt.normalizePath)(`${n.fleetFolder}/channels/${e}/bindings.json`),i=JSON.stringify(s,null,2);try{let o=this.deps.vault.getAbstractFileByPath(r);if(o instanceof xt.TFile)await this.deps.vault.modify(o,i);else{let l=r.slice(0,r.lastIndexOf("/"));if(!this.deps.vault.getAbstractFileByPath(l))try{await this.deps.vault.createFolder(l)}catch{}await this.deps.vault.create(r,i)}}catch(o){console.warn(`Agent Fleet: failed to persist thread bindings for ${e}`,o)}}async loadBindings(e){let t=this.deps.getSettings(),s=(0,xt.normalizePath)(`${t.fleetFolder}/channels/${e}/bindings.json`);try{let n=this.deps.vault.getAbstractFileByPath(s);if(!(n instanceof xt.TFile))return;let r=await this.deps.vault.cachedRead(n),i=JSON.parse(r);for(let[o,l]of Object.entries(i))typeof l=="string"&&this.threadBindings.set(`${e}:${o}`,l)}catch{}}getThreadAgent(e,t){return this.threadBindings.get(`${e}:${t}`)}enforceHardCap(){let e=Math.max(1,this.deps.getSettings().maxConcurrentChannelSessions),t=Array.from(this.sessions.values()).filter(n=>n.session.isProcessAlive&&!n.session.isStreaming);if(t.length<=e)return;t.sort((n,r)=>n.session.lastActiveAt-r.session.lastActiveAt);let s=t.length-e;for(let n=0;n<s;n+=1){let r=t[n];if(!r)break;try{r.session.hibernate()}catch{}}}async runHibernationSweep(){let e=Math.max(6e4,this.deps.getSettings().channelIdleTimeoutMinutes*6e4),t=this.now()-e;for(let s of this.sessions.values())if(s.session.isProcessAlive&&!s.session.isStreaming&&s.session.lastActiveAt<t)try{s.session.hibernate()}catch{}}async broadcastToChannel(e,t){let s=this.adapters.get(e);if(!s){console.warn(`Agent Fleet: broadcastToChannel \u2014 no adapter for channel ${e}`);return}if(!s.broadcast){console.warn(`Agent Fleet: broadcastToChannel \u2014 adapter ${e} does not support broadcast`);return}await s.broadcast(t)}async postToChannelTarget(e,t,s){let n=this.adapters.get(e);if(!n){console.warn(`Agent Fleet: postToChannelTarget \u2014 no adapter for channel ${e}`);return}if(!n.sendToTarget){console.warn(`Agent Fleet: postToChannelTarget \u2014 adapter ${e} does not support sendToTarget`);return}await n.sendToTarget(t,s)}conversationLockGen=new Map;async withConversationLock(e,t){let s=this.conversationLocks.get(e)??Promise.resolve(),n,r=new Promise(o=>{n=o}),i=(this.conversationLockGen.get(e)??0)+1;this.conversationLockGen.set(e,i),this.conversationLocks.set(e,s.then(()=>r));try{await s,await t()}finally{n(),this.conversationLockGen.get(e)===i&&(this.conversationLocks.delete(e),this.conversationLockGen.delete(e))}}ensureMetrics(e){let t=this.metrics.get(e);return t||(t={messagesReceived:0,messagesSent:0,lastMessageAt:null},this.metrics.set(e,t)),t}getMetrics(e){return{...this.ensureMetrics(e)}}getChannelStatus(e){let t=this.adapters.get(e);return t?t.getStatus():"disabled"}getConnectedCount(){let e=0;for(let t of this.adapters.values())t.getStatus()==="connected"&&(e+=1);return e}getSessionCount(e){let t=0,s=`${e}:`;for(let n of this.sessions.keys())n.startsWith(s)&&(t+=1);return t}onStatusChange(e){return this.statusListeners.add(e),()=>this.statusListeners.delete(e)}notifyStatusListeners(){for(let e of this.statusListeners)try{e()}catch{}}};function Qd(a){if(a.length===0)return"";let e=new Map;for(let s of a)e.set(s.name,(e.get(s.name)??0)+1);let t=[];for(let[s,n]of e)t.push(n>1?`${s}\xD7${n}`:s);return`Used ${a.length} tool${a.length===1?"":"s"}: ${t.join(", ")}`}var aa=class{credentials=new Map;secretStore;persistCallback;setSecretStore(e){this.secretStore=e}loadCredentials(e){if(this.credentials.clear(),this.secretStore?.available){let t=this.secretStore.listByPrefix(gs);for(let s of t){let n=gs+"-",r=s.startsWith(n)?s.slice(n.length):s,i=this.secretStore.getJson(gs,r);if(i){let o=i._ref??r,l={...i};delete l._ref,this.credentials.set(o,l)}}}if(this.credentials.size===0&&e){for(let[t,s]of Object.entries(e))this.credentials.set(t,s);this.secretStore?.available&&this.credentials.size>0&&this.persistToSecretStore()}}onChanged(e){this.persistCallback=e}get(e){return this.credentials.get(e)}set(e,t){this.credentials.set(e,t),this.persist()}delete(e){this.credentials.delete(e),this.secretStore?.delete(gs,e),this.persist()}list(){return Array.from(this.credentials.entries()).map(([e,t])=>({ref:e,entry:t}))}toRecord(){let e={};for(let[t,s]of this.credentials.entries())e[t]=s;return e}persist(){this.persistToSecretStore(),this.persistCallback&&this.persistCallback(this.toRecord())}persistToSecretStore(){if(this.secretStore?.available)for(let[e,t]of this.credentials)this.secretStore.setJson(gs,e,{...t,_ref:e})}};function _o(){return{status:"disconnected",scope:"user",tools:[],toolDetails:[]}}function Zd(a,e,t){if(t)return"stdio";let s=(a??"").toLowerCase();return s==="sse"?"sse":s==="http"||s==="streamable-http"||s==="streamable_http"?"http":e?.endsWith("/sse")?"sse":"http"}function Ao(a){let e=[],t={},s;try{s=JSON.parse(a)}catch{return{servers:e,tokens:t}}let n=s.mcpServers;if(!n||typeof n!="object")return{servers:e,tokens:t};for(let[r,i]of Object.entries(n)){if(!i||typeof i!="object")continue;let o=i,l=typeof o.command=="string"?o.command:void 0,c=typeof o.url=="string"?o.url:void 0;if(!l&&!c)continue;let d=Zd(typeof o.type=="string"?o.type:void 0,c,!!l),u={name:r,type:d,enabled:!0,source:"imported",..._o()};if(d==="stdio")u.command=l,Array.isArray(o.args)&&(u.args=o.args.filter(h=>typeof h=="string")),o.env&&typeof o.env=="object"&&(u.env=To(o.env));else{u.url=c;let h=o.headers&&typeof o.headers=="object"?To(o.headers):{},p=h.Authorization??h.authorization;p?.startsWith("Bearer ")?(t[r]=p.slice(7),delete h.Authorization,delete h.authorization,u.auth="oauth"):u.auth="none",Object.keys(h).length>0&&(u.headers=h)}e.push(u)}return{servers:e,tokens:t}}function Po(a){let e=new Map,t=null;for(let n of a.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;let i=r.match(/^\[(.+)\]$/);if(i){let h=i[1].trim().match(/^mcp_servers\.(.+)$/);if(!h){t=null;continue}let p=h[1],m=null;p.endsWith(".env")?(m="env",p=p.slice(0,-4)):p.endsWith(".oauth")&&(m="oauth",p=p.slice(0,-6));let f=ra(p);if(!f){t=null;continue}e.has(f)||e.set(f,{name:f,enabled:!0}),t={name:f,sub:m};continue}if(!t)continue;let o=r.match(/^([^=]+?)\s*=\s*(.+)$/);if(!o)continue;let l=ra(o[1].trim()),c=o[2].trim(),d=e.get(t.name);if(t.sub==="env")d.env??={},d.env[l]=vs(c);else if(t.sub==="oauth")l==="client_id"&&(d.oauthClientId=vs(c));else switch(l){case"command":d.command=vs(c);break;case"args":d.args=eu(c);break;case"url":d.url=vs(c);break;case"bearer_token_env_var":d.bearerEnvVar=vs(c);break;case"oauth_resource":d.oauthResource=vs(c);break;case"enabled":d.enabled=c==="true";break;default:break}}let s=[];for(let n of e.values()){if(!n.command&&!n.url)continue;let r=n.command?"stdio":n.url?.endsWith("/sse")?"sse":"http",i={name:n.name,type:r,enabled:n.enabled,source:"imported",..._o()};r==="stdio"?(i.command=n.command,n.args&&n.args.length>0&&(i.args=n.args),n.env&&Object.keys(n.env).length>0&&(i.env=n.env)):(i.url=n.url,n.oauthClientId||n.oauthResource?(i.auth="oauth",i.oauth={clientId:n.oauthClientId,resource:n.oauthResource}):n.bearerEnvVar?(i.auth="bearer",i.envSecretKeys=[n.bearerEnvVar]):i.auth="none"),s.push(i)}return{servers:s,tokens:{}}}function Eo(...a){let e=new Map,t={};for(let s of a){for(let n of s.servers){let r=n.name.trim().toLowerCase();e.has(r)||e.set(r,n)}Object.assign(t,s.tokens)}return{servers:[...e.values()],tokens:t}}function ra(a){let e=a.trim();return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function vs(a){let e=a.trim();if(e.startsWith('"')||e.startsWith("'")){let t=e[0],s=e.indexOf(t,1);if(s>0)return e.slice(1,s)}return ra(e.replace(/\s+#.*$/,""))}function eu(a){let e=a.trim();try{let s=JSON.parse(e);if(Array.isArray(s))return s.filter(n=>typeof n=="string")}catch{}return e.replace(/^\[/,"").replace(/\]$/,"").split(",").map(s=>ra(s.trim())).filter(Boolean)}function To(a){let e={};for(let[t,s]of Object.entries(a))typeof s=="string"&&(e[t]=s);return e}var kh=st(Cl(),1),xh=st(ma(),1),Sh=st(ks(),1),Ch=st(Tr(),1),Th=st(Pr(),1),_h=st(Fr(),1),Ml=st(va(),1),Ah=st(Il(),1);var As=Ml.default;var Fl=require("obsidian");var Ht=class{base;cap;delayMs;constructor(e=1e3,t=3e4){this.base=e,this.cap=t,this.delayMs=e}nextDelay(){let e=this.delayMs;return this.delayMs=Math.min(this.cap,this.delayMs*2),e}reset(){this.delayMs=this.base}};var Ph="https://slack.com/api";function Eh(a){let e=a.team??"unknown",t=a.channel??"unknown",s=a.thread_ts??a.ts??"unknown";return`slack:${e}:${t}:thread:${s}`}function Dh(a){let e=a.split(":");return e.length>=3&&e[0]==="slack"?e[2]??null:null}function Rh(a){let e=a.split(":");if(e[3]==="thread"&&e[4])return e[4]}var ba=class{type="slack";config;credential;ws=null;status="stopped";stopping=!1;backoff=new Ht;reconnectTimer=null;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;sendQueues=new Map;threadContext=new Map;constructor(e,t){if(t.type!=="slack")throw new Error(`SlackAdapter requires a slack credential, got ${t.type}`);this.config=e,this.credential=t}async start(){this.stopping=!1,await this.connect()}async stop(){if(this.stopping=!0,this.reconnectTimer&&(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws){try{this.ws.close()}catch{}this.ws=null}this.threadContext.clear(),this.sendQueues.clear(),this.setStatus("stopped")}getStatus(){return this.status}async send(e,t){let s=Dh(e);if(!s){console.warn(`Agent Fleet: could not extract channel id from ${e}`);return}let n=Rh(e),r=Qs(t);await this.enqueueSend(s,async()=>{await this.slackApi("chat.postMessage",{channel:s,text:r,...n?{thread_ts:n}:{}})})}async sendToTarget(e,t){if(!e)return;let s=Qs(t);await this.enqueueSend(e,async()=>{await this.slackApi("chat.postMessage",{channel:e,text:s})})}async broadcast(e){let t=this.config.allowedUsers[0];if(!t){console.warn(`Agent Fleet: broadcast on ${this.config.name} skipped \u2014 no allowed users configured`);return}try{let n=(await this.slackApi("conversations.open",{users:t})).channel?.id;if(!n){console.warn(`Agent Fleet: broadcast \u2014 conversations.open returned no channel for user ${t}`);return}let r=Qs(e);await this.slackApi("chat.postMessage",{channel:n,text:r})}catch(s){console.error(`Agent Fleet: broadcast failed on ${this.config.name}`,s)}}async setThreadTitle(e,t){let s=this.threadContext.get(e);if(s)try{await this.slackApi("assistant.threads.setTitle",{channel_id:s.channelId,thread_ts:s.threadTs,title:t})}catch(n){console.warn(`Agent Fleet: assistant.threads.setTitle failed on ${this.config.name}`,n)}}async setTyping(e,t){let s=this.threadContext.get(e);if(s)try{await this.slackApi("assistant.threads.setStatus",{channel_id:s.channelId,thread_ts:s.threadTs,status:t?"is thinking...":""})}catch(n){console.warn(`Agent Fleet: assistant.threads.setStatus (${t?"on":"off"}) failed on ${this.config.name}`,n)}}onInbound(e){return this.inboundHandlers.add(e),()=>this.inboundHandlers.delete(e)}onStatusChange(e){return this.statusHandlers.add(e),()=>this.statusHandlers.delete(e)}setAllowedAgentsResolver(e){this.allowedAgentsResolver=e}onAgentSwitch(e){return this.agentSwitchHandlers.add(e),()=>this.agentSwitchHandlers.delete(e)}async connect(){if(this.stopping)return;this.setStatus(this.ws?"reconnecting":"connecting");let e;try{let t=await this.slackApi("apps.connections.open",{},{useAppToken:!0});if(!t.ok||!t.url)throw new Error(t.error??"apps.connections.open returned no URL");e=t.url}catch(t){console.error(`Agent Fleet: Slack apps.connections.open failed for channel ${this.config.name}`,t),this.setStatus("needs-auth"),this.scheduleReconnect();return}try{let t=new As(e);t.on("open",()=>{}),t.on("message",r=>{this.handleSocketData(r)}),t.on("error",r=>{console.warn(`Agent Fleet: Slack WebSocket error on ${this.config.name}`,r),this.setStatus("error")}),t.on("close",()=>{this.ws=null,this.stopping||this.scheduleReconnect()}),this.ws=t;let s=window.setTimeout(()=>{if(this.status==="connecting"||this.status==="reconnecting"){console.warn(`Agent Fleet: Slack WebSocket connect timeout on ${this.config.name}`);try{t.close()}catch{}}},3e4);t.on("close",()=>window.clearTimeout(s));let n=this.onStatusChange(r=>{r==="connected"&&(window.clearTimeout(s),n())})}catch(t){console.error("Agent Fleet: Slack WebSocket open failed",t),this.setStatus("error"),this.scheduleReconnect();return}}handleSocketData(e){let t;try{t=JSON.parse(e.toString())}catch{return}if(t.type==="hello"){this.backoff.reset(),this.setStatus("connected");return}if(t.type==="disconnect"){try{this.ws?.close()}catch{}return}if(t.type==="events_api"&&t.envelope_id){this.ackEnvelope(t.envelope_id),this.routeEventPayload(t.payload);return}if(t.type==="slash_commands"&&t.envelope_id){this.ackEnvelope(t.envelope_id),this.handleSlashCommand(t.payload);return}if(t.type==="interactive"&&t.envelope_id){this.ackEnvelope(t.envelope_id),this.handleInteraction(t.payload);return}t.envelope_id&&this.ackEnvelope(t.envelope_id)}async handleSlashCommand(e){if(!e)return;let t=e.command,s=e.channel_id,n=e.user_id;if(!(!t||!s||!n)){if(t==="/agents"){let r=this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents;if(r.length===0){await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file."});return}let i=r.map(l=>({type:"button",text:{type:"plain_text",text:l===this.config.defaultAgent?`${l} \u2713`:l,emoji:!0},action_id:`switch_agent_${l}`,value:l})),o=[{type:"section",text:{type:"mrkdwn",text:"*Select an agent to chat with:*"}}];for(let l=0;l<i.length;l+=5)o.push({type:"actions",elements:i.slice(l,l+5)});try{await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:"Select an agent",blocks:o})}catch(l){console.error("Agent Fleet: /agents response failed",l)}return}try{await this.slackApi("chat.postEphemeral",{channel:s,user:n,text:`Unknown command: ${t}`})}catch(r){console.error(`Agent Fleet: slash command response failed for ${t}`,r)}}}async handleInteraction(e){if(!e||e.type!=="block_actions")return;let s=e.actions,n=e.user,r=e.channel;if(!s?.length||!n||!r)return;let i=s[0];if(!i)return;let o=i.action_id,l=i.value;if(!o?.startsWith("switch_agent_")||!l)return;let c=n.id,d=r.id;if(!c||!d)return;let h=`slack:${e.team?.id??"unknown"}:${d}:user:${c}`;for(let p of this.agentSwitchHandlers)try{p(h,l,c)}catch(m){console.error("Agent Fleet: agent switch handler threw",m)}try{await this.slackApi("chat.postEphemeral",{channel:d,user:c,text:`Switched to *${l}*. Send your next message to start.`})}catch(p){console.warn("Agent Fleet: agent switch confirmation failed",p)}try{await this.setThreadTitle(h,l)}catch{}}ackEnvelope(e){if(!(!this.ws||this.ws.readyState!==As.OPEN))try{this.ws.send(JSON.stringify({envelope_id:e}))}catch(t){console.warn("Agent Fleet: Slack envelope ACK failed",t)}}routeEventPayload(e){if(!e)return;let t=e.event;if(!t)return;let s=t.type;if(s==="assistant_thread_started"){let d=t.assistant_thread;d?.channel_id&&d.thread_ts&&console.debug(`Agent Fleet: assistant thread started on ${this.config.name} (channel=${d.channel_id}, thread_ts=${d.thread_ts}, user=${d.user_id})`);return}if(s==="assistant_thread_context_changed")return;let n=t,r=s==="message"&&n.subtype===void 0,i=s==="app_mention";if(!r&&!i||n.bot_id||!n.user||!n.text||i&&(n.text=n.text.replace(/^<@[A-Z0-9]+>\s*/,"").trim(),!n.text))return;let o=Eh(n),l=n.thread_ts??n.ts;if(n.channel&&l&&(this.threadContext.set(o,{channelId:n.channel,threadTs:l}),this.threadContext.size>500)){let u=this.threadContext.keys().next();u.done||this.threadContext.delete(u.value)}let c={conversationId:o,externalUserId:n.user,text:n.text,timestamp:new Date().toISOString(),meta:{slack_channel:n.channel,slack_ts:n.ts,thread_ts:n.thread_ts}};for(let d of this.inboundHandlers)try{d(c)}catch(u){console.error("Agent Fleet: Slack inbound handler threw",u)}}scheduleReconnect(){if(this.stopping||this.reconnectTimer)return;let e=this.backoff.nextDelay();console.warn(`Agent Fleet: Slack channel ${this.config.name} scheduling reconnect in ${e}ms`),this.reconnectTimer=window.setTimeout(()=>{this.reconnectTimer=null,!this.stopping&&this.connect()},e)}setStatus(e){if(this.status!==e){this.status=e;for(let t of this.statusHandlers)try{t(e)}catch{}}}async slackApi(e,t,s={}){let n=s.useAppToken?this.credential.appToken:this.credential.botToken,r=`${Ph}/${e}`,i=await(0,Fl.requestUrl)({url:r,method:"POST",contentType:"application/json; charset=utf-8",headers:{Authorization:`Bearer ${n}`},body:JSON.stringify(t),throw:!1});if(i.status===429){let l=Number(i.headers["retry-after"]??"1");return await new Promise(c=>window.setTimeout(c,Math.max(1e3,l*1e3))),this.slackApi(e,t,s)}if(i.status<200||i.status>=300)throw new Error(`Slack ${e} HTTP ${i.status}`);let o=i.json;if(o.ok===!1)throw new Error(`Slack ${e} error: ${o.error??"unknown"}`);return o}async enqueueSend(e,t){let n=(this.sendQueues.get(e)??Promise.resolve()).then(async()=>{try{await t()}finally{await new Promise(i=>window.setTimeout(i,1e3))}}),r=n.catch(i=>{console.warn(`Agent Fleet: Slack send queue error for ${e}`,i)});this.sendQueues.set(e,r);try{await n}finally{this.sendQueues.get(e)===r&&this.sendQueues.delete(e)}}};var Or=require("obsidian");var Ll="https://api.telegram.org",ka=class{type="telegram";config;credential;status="stopped";stopping=!1;pollOffset=0;pollTimer=null;backoff=new Ht;typingIntervals=new Map;pollAbort=null;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;constructor(e,t){if(t.type!=="telegram")throw new Error(`TelegramAdapter requires a telegram credential, got ${t.type}`);this.config=e,this.credential=t}async start(){this.stopping=!1;try{let t=(await this.tgApi("getUpdates",{offset:-1,limit:1})).result?.[0];t&&(this.pollOffset=t.update_id+1)}catch{}try{await this.tgApi("setMyCommands",{commands:[{command:"agents",description:"List available agents"}]})}catch{}this.setStatus("connected"),this.poll()}async stop(){this.stopping=!0,this.pollTimer&&(window.clearTimeout(this.pollTimer),this.pollTimer=null),this.pollAbort?.abort(),this.pollAbort=null;for(let[,e]of this.typingIntervals)window.clearInterval(e);this.typingIntervals.clear(),this.setStatus("stopped")}getStatus(){return this.status}async send(e,t){let s=Ol(e);if(!s)return;let n=Nl(e),r=ss(t,4096);for(let i of r)await this.tgApi("sendMessage",{chat_id:s,text:i,parse_mode:"Markdown",...n?{message_thread_id:Number(n)}:{}})}async sendToTarget(e,t){if(!e)return;let s=ss(t,4096);for(let n of s)await this.tgApi("sendMessage",{chat_id:e,text:n,parse_mode:"Markdown"})}async setTyping(e,t){let s=Ol(e);if(!s)return;let n=Nl(e),r={chat_id:s,action:"typing"};if(n&&(r.message_thread_id=Number(n)),t){let i=this.typingIntervals.get(e);i&&window.clearInterval(i);try{await this.tgApi("sendChatAction",r)}catch(l){console.warn("Agent Fleet: Telegram sendChatAction failed",l)}let o=window.setInterval(()=>{this.tgApi("sendChatAction",r).catch(()=>{})},4500);this.typingIntervals.set(e,o)}else{let i=this.typingIntervals.get(e);i&&(window.clearInterval(i),this.typingIntervals.delete(e))}}async setThreadTitle(e,t){}async broadcast(e){let t=this.config.allowedUsers[0];if(t)try{let s=ss(e,4096);for(let n of s)await this.tgApi("sendMessage",{chat_id:t,text:n,parse_mode:"Markdown"})}catch(s){console.error(`Agent Fleet: Telegram broadcast failed on ${this.config.name}`,s)}}onInbound(e){return this.inboundHandlers.add(e),()=>this.inboundHandlers.delete(e)}onStatusChange(e){return this.statusHandlers.add(e),()=>this.statusHandlers.delete(e)}setAllowedAgentsResolver(e){this.allowedAgentsResolver=e}pickerAgents(){return this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents}onAgentSwitch(e){return this.agentSwitchHandlers.add(e),()=>this.agentSwitchHandlers.delete(e)}poll(){this.stopping||(async()=>{try{this.pollAbort=new AbortController;let e=await this.tgApi("getUpdates",{offset:this.pollOffset,timeout:30,allowed_updates:["message","callback_query"]},this.pollAbort.signal);if(e.ok&&e.result)for(let t of e.result){if(this.pollOffset=t.update_id+1,t.callback_query){this.handleCallbackQuery(t.callback_query);continue}t.message&&this.routeMessage(t.message)}this.backoff.reset(),this.status!=="connected"&&this.setStatus("connected")}catch(e){if(e instanceof DOMException&&e.name==="AbortError")return;if(console.warn(`Agent Fleet: Telegram poll failed on ${this.config.name}`,e),this.status!=="error"&&this.status!=="needs-auth"){let t=e instanceof Error?e.message:String(e);this.setStatus(t.includes("401")||t.includes("Unauthorized")?"needs-auth":"error")}await new Promise(t=>window.setTimeout(t,this.backoff.nextDelay()))}this.stopping||(this.pollTimer=window.setTimeout(()=>this.poll(),100))})()}routeMessage(e){let t=e.photo&&e.photo.length>0,s=e.document&&this.isImageMime(e.document.mime_type),n=!!e.text;if(!e.from||!n&&!t&&!s)return;let r=e.text??e.caption??"";if(r==="/agents"||r.startsWith("/agents@")){this.handleAgentsCommand(e);return}if(r.startsWith("/"))return;let i=String(e.from.id),o=String(e.chat.id),l=e.message_thread_id?String(e.message_thread_id):void 0,c=l?`tg:${o}:topic:${l}`:`tg:${o}`;this.buildAndEmitMessage(e,r,c,i,o,l)}async buildAndEmitMessage(e,t,s,n,r,i){let o=[];try{if(e.photo&&e.photo.length>0){let c=e.photo[e.photo.length-1],d=await this.downloadFile(c.file_id,`photo_${e.message_id}.jpg`,"image/jpeg");d&&o.push(d)}if(e.document&&this.isImageMime(e.document.mime_type)){let c=e.document.file_name??`doc_${e.message_id}`,d=e.document.mime_type??"image/jpeg",u=await this.downloadFile(e.document.file_id,c,d);u&&o.push(u)}}catch(c){console.warn("Agent Fleet: Telegram image download failed",c)}let l={conversationId:s,externalUserId:n,text:t,timestamp:new Date(e.date*1e3).toISOString(),meta:{telegram_chat_id:r,telegram_message_id:e.message_id,telegram_thread_id:i,chat_type:e.chat.type},...o.length>0?{images:o}:{}};for(let c of this.inboundHandlers)try{c(l)}catch(d){console.error("Agent Fleet: Telegram inbound handler threw",d)}}async downloadFile(e,t,s){let r=(await this.tgApi("getFile",{file_id:e})).result?.file_path;if(!r)return null;let i=`${Ll}/file/bot${this.credential.botToken}/${r}`;return{data:(await(0,Or.requestUrl)({url:i,method:"GET"})).arrayBuffer,filename:t,mimeType:s}}isImageMime(e){return e?e==="image/jpeg"||e==="image/png"||e==="image/gif"||e==="image/webp"||e==="image/bmp"||e==="image/tiff":!1}async handleAgentsCommand(e){let t=String(e.chat.id),s=e.message_thread_id,n=this.pickerAgents();if(n.length===0){await this.tgApi("sendMessage",{chat_id:t,text:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file.",...s?{message_thread_id:s}:{}});return}let r=n.map(i=>[{text:i===this.config.defaultAgent?`${i} \u2713`:i,callback_data:`switch:${i}`}]);await this.tgApi("sendMessage",{chat_id:t,text:"*Select an agent to chat with:*",parse_mode:"Markdown",reply_markup:{inline_keyboard:r},...s?{message_thread_id:s}:{}})}async handleCallbackQuery(e){let t=e.data;if(!t?.startsWith("switch:")){await this.tgApi("answerCallbackQuery",{callback_query_id:e.id});return}let s=t.slice(7),n=String(e.from.id),r=String(e.message?.chat?.id??e.from.id),i=e.message?.message_thread_id?String(e.message.message_thread_id):void 0,o=i?`tg:${r}:topic:${i}`:`tg:${r}`;for(let l of this.agentSwitchHandlers)try{l(o,s,n)}catch(c){console.error("Agent Fleet: Telegram agent switch handler threw",c)}if(await this.tgApi("answerCallbackQuery",{callback_query_id:e.id,text:`Switched to ${s}`}),e.message){let c=this.pickerAgents().map(d=>[{text:d===s?`${d} \u2713`:d,callback_data:`switch:${d}`}]);try{await this.tgApi("editMessageText",{chat_id:r,message_id:e.message.message_id,text:`*Active agent: ${s}*`,parse_mode:"Markdown",reply_markup:{inline_keyboard:c}})}catch{}}}async tgApi(e,t,s){if(s?.aborted)throw new DOMException("Aborted","AbortError");let n=`${Ll}/bot${this.credential.botToken}/${e}`,r=(0,Or.requestUrl)({url:n,method:"POST",contentType:"application/json",body:JSON.stringify(t),throw:!1}),i;if(s?i=await Promise.race([r,new Promise((o,l)=>{s.addEventListener("abort",()=>l(new DOMException("Aborted","AbortError")),{once:!0})})]):i=await r,i.status===401||i.status===403)throw new Error(`Telegram ${e} ${i.status} Unauthorized`);if(i.status===429){let l=i.json?.parameters?.retry_after??1;return await new Promise(c=>window.setTimeout(c,l*1e3)),this.tgApi(e,t)}if(i.status<200||i.status>=300)throw new Error(`Telegram ${e} HTTP ${i.status}: ${i.text}`);return i.json}setStatus(e){if(this.status!==e){this.status=e;for(let t of this.statusHandlers)try{t(e)}catch{}}}};function Ol(a){return a.startsWith("tg:")?a.split(":")[1]??null:null}function Nl(a){let e=a.split(":");if(e[2]==="topic"&&e[3])return e[3]}var Br=require("obsidian");var Ih="https://discord.com/api/v10",Mh="wss://gateway.discord.gg",Fh="?v=10&encoding=json",Lh="DiscordBot (https://github.com/denberek/obsidian-agent-fleet, 0.13.6)",Oh=37376,Nh=0,Nr=1,Bh=2,Uh=6,$h=7,jh=9,Hh=10,Wh=11,qh=2,zh=3,Bl=4,Gh=7,Ul=64,xa=class{type="discord";config;credential;ws=null;status="stopped";stopping=!1;backoff=new Ht;reconnectTimer=null;sessionId=null;resumeGatewayUrl=null;seq=null;canResume=!1;heartbeatTimer=null;heartbeatInitialTimer=null;heartbeatAcked=!0;selfUserId=null;applicationId=null;commandRegistered=!1;warnedEmptyContent=!1;typingIntervals=new Map;sendQueues=new Map;inboundHandlers=new Set;statusHandlers=new Set;agentSwitchHandlers=new Set;allowedAgentsResolver;constructor(e,t){if(t.type!=="discord")throw new Error(`DiscordAdapter requires a discord credential, got ${t.type}`);this.config=e,this.credential=t}async start(){this.stopping=!1,this.backoff.reset(),this.canResume=!1,await this.connect()}async stop(){this.stopping=!0,this.reconnectTimer&&(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.clearHeartbeat();for(let[,e]of this.typingIntervals)window.clearInterval(e);this.typingIntervals.clear();try{this.ws?.close()}catch{}this.ws=null,this.setStatus("stopped")}getStatus(){return this.status}async send(e,t){let s=jl(e);s&&await this.sendToTarget(s,t)}async sendToTarget(e,t){if(!e)return;let s=ss(t,2e3);await this.enqueueSend(e,async()=>{for(let n of s)await this.discordApi("POST",`/channels/${e}/messages`,{content:n})})}async setTyping(e,t){let s=jl(e);if(s)if(t){let n=this.typingIntervals.get(e);n&&window.clearInterval(n);try{await this.discordApi("POST",`/channels/${s}/typing`)}catch(i){console.warn("Agent Fleet: Discord typing trigger failed",i)}let r=window.setInterval(()=>{this.discordApi("POST",`/channels/${s}/typing`).catch(()=>{})},8e3);this.typingIntervals.set(e,r)}else{let n=this.typingIntervals.get(e);n&&(window.clearInterval(n),this.typingIntervals.delete(e))}}async broadcast(e){let t=this.config.allowedUsers[0];if(t)try{let n=(await this.discordApi("POST","/users/@me/channels",{recipient_id:t}))?.id;if(!n)return;let r=ss(e,2e3);for(let i of r)await this.discordApi("POST",`/channels/${n}/messages`,{content:i})}catch(s){console.error(`Agent Fleet: Discord broadcast failed on ${this.config.name}`,s)}}onInbound(e){return this.inboundHandlers.add(e),()=>this.inboundHandlers.delete(e)}onStatusChange(e){return this.statusHandlers.add(e),()=>this.statusHandlers.delete(e)}onAgentSwitch(e){return this.agentSwitchHandlers.add(e),()=>this.agentSwitchHandlers.delete(e)}setAllowedAgentsResolver(e){this.allowedAgentsResolver=e}pickerAgents(){return this.allowedAgentsResolver?this.allowedAgentsResolver():this.config.allowedAgents}async connect(){if(this.stopping)return;this.setStatus(this.ws?"reconnecting":"connecting");let t=`${this.canResume&&this.resumeGatewayUrl?this.resumeGatewayUrl:Mh}${Fh}`;try{let s=new As(t);s.on("message",i=>{this.handleFrame(i)}),s.on("error",i=>{console.warn(`Agent Fleet: Discord WebSocket error on ${this.config.name}`,i)}),s.on("close",i=>{this.ws=null,this.clearHeartbeat(),this.handleClose(i)}),this.ws=s;let n=window.setTimeout(()=>{if(this.status==="connecting"||this.status==="reconnecting"){console.warn(`Agent Fleet: Discord WebSocket connect timeout on ${this.config.name}`);try{s.close()}catch{}}},3e4);s.on("close",()=>window.clearTimeout(n));let r=this.onStatusChange(i=>{i==="connected"&&(window.clearTimeout(n),r())})}catch(s){console.error("Agent Fleet: Discord WebSocket open failed",s),this.setStatus("error"),this.scheduleReconnect()}}handleClose(e){let t=!1;e===4014?(console.error(`Agent Fleet: Discord channel ${this.config.name} \u2014 disallowed intents (4014). Enable the Message Content intent in the Developer Portal \u2192 your app \u2192 Bot \u2192 Privileged Gateway Intents, then reload.`),this.canResume=!1,this.setStatus("needs-auth"),t=!0):e===4004||e===4013?(console.error(`Agent Fleet: Discord channel ${this.config.name} \u2014 gateway auth/intents error (${e}). Check the bot token credential, then reload.`),this.canResume=!1,this.setStatus("needs-auth"),t=!0):(e===4007||e===4009)&&(this.canResume=!1),!this.stopping&&!t&&this.scheduleReconnect()}handleFrame(e){let t;try{t=JSON.parse(e.toString())}catch{return}switch(typeof t.s=="number"&&(this.seq=t.s),t.op){case Hh:{let s=t.d?.heartbeat_interval;this.startHeartbeat(s??41250),this.canResume&&this.sessionId&&this.seq!==null?this.sendGateway(Uh,{token:this.credential.botToken,session_id:this.sessionId,seq:this.seq}):this.identify();return}case Nr:{this.sendGateway(Nr,this.seq);return}case Wh:{this.heartbeatAcked=!0;return}case $h:{try{this.ws?.close()}catch{}return}case jh:{t.d===!0||(this.canResume=!1,this.sessionId=null),window.setTimeout(()=>{try{this.ws?.close()}catch{}},1e3+Math.floor(Math.random()*4e3));return}case Nh:{this.handleDispatch(t.t??"",t.d);return}default:return}}handleDispatch(e,t){if(e==="READY"){let s=t;this.sessionId=s.session_id??null,this.resumeGatewayUrl=s.resume_gateway_url??null,this.selfUserId=s.user?.id??null,this.applicationId=s.application?.id??null,this.canResume=!0,this.backoff.reset(),this.setStatus("connected"),this.registerAgentsCommand();return}if(e==="RESUMED"){this.backoff.reset(),this.setStatus("connected");return}if(e==="MESSAGE_CREATE"){this.routeMessage(t);return}if(e==="INTERACTION_CREATE"){this.handleInteraction(t);return}}identify(){this.sendGateway(Bh,{token:this.credential.botToken,intents:Oh,properties:{os:"linux",browser:"agent-fleet",device:"agent-fleet"}})}sendGateway(e,t){if(!(!this.ws||this.ws.readyState!==As.OPEN))try{this.ws.send(JSON.stringify({op:e,d:t}))}catch(s){console.warn("Agent Fleet: Discord gateway send failed",s)}}startHeartbeat(e){this.clearHeartbeat(),this.heartbeatAcked=!0;let t=()=>{if(!this.heartbeatAcked){console.warn(`Agent Fleet: Discord heartbeat not ACKed on ${this.config.name} \u2014 reconnecting`);try{this.ws?.close()}catch{}return}this.heartbeatAcked=!1,this.sendGateway(Nr,this.seq)};this.heartbeatInitialTimer=window.setTimeout(()=>{t(),this.heartbeatTimer=window.setInterval(t,e)},Math.floor(e*Math.random()))}clearHeartbeat(){this.heartbeatInitialTimer&&(window.clearTimeout(this.heartbeatInitialTimer),this.heartbeatInitialTimer=null),this.heartbeatTimer&&(window.clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}scheduleReconnect(){if(this.stopping||this.reconnectTimer)return;let e=this.backoff.nextDelay();console.warn(`Agent Fleet: Discord channel ${this.config.name} scheduling reconnect in ${e}ms`),this.reconnectTimer=window.setTimeout(()=>{this.reconnectTimer=null,!this.stopping&&this.connect()},e)}routeMessage(e){if(!e.author||e.author.bot||this.selfUserId&&e.author.id===this.selfUserId||!e.channel_id)return;let t=(e.attachments??[]).filter(r=>typeof r.content_type=="string"&&r.content_type.startsWith("image/")),s=Vh(e.content??"",this.selfUserId);if(!s&&t.length===0){this.warnedEmptyContent||(this.warnedEmptyContent=!0,console.warn(`Agent Fleet: Discord channel ${this.config.name} received a message with empty content. If this persists, enable the Message Content intent in the Developer Portal.`));return}let n=$l(e.guild_id,e.channel_id);this.buildAndEmitMessage(e,s,n,t)}async buildAndEmitMessage(e,t,s,n){let r=[];for(let o of n)try{let l=await(0,Br.requestUrl)({url:o.url,method:"GET"});r.push({data:l.arrayBuffer,filename:o.filename||`attachment_${e.id}`,mimeType:o.content_type??"image/jpeg"})}catch(l){console.warn("Agent Fleet: Discord attachment download failed",l)}let i={conversationId:s,externalUserId:e.author.id,text:t,timestamp:e.timestamp??new Date().toISOString(),meta:{discord_guild_id:e.guild_id,discord_channel_id:e.channel_id,discord_message_id:e.id,is_dm:!e.guild_id},...r.length>0?{images:r}:{}};for(let o of this.inboundHandlers)try{o(i)}catch(l){console.error("Agent Fleet: Discord inbound handler threw",l)}}async registerAgentsCommand(){if(!(this.commandRegistered||!this.applicationId))try{await this.discordApi("PUT",`/applications/${this.applicationId}/commands`,[{name:"agents",description:"Switch the active agent",type:1}]),this.commandRegistered=!0}catch(e){console.warn(`Agent Fleet: Discord /agents command registration failed on ${this.config.name}`,e)}}async handleInteraction(e){if(e.type===qh){e.data?.name==="agents"&&await this.respondWithAgentPicker(e);return}if(e.type===zh){let t=e.data?.custom_id??"";if(!t.startsWith("switch:"))return;let s=t.slice(7),n=e.member?.user?.id??e.user?.id,r=e.channel_id;if(!n||!r)return;let i=$l(e.guild_id,r);for(let o of this.agentSwitchHandlers)try{o(i,s,n)}catch(l){console.error("Agent Fleet: Discord agent switch handler threw",l)}await this.respondToInteraction(e,Gh,{content:`Active agent: **${s}**`,components:this.buildAgentButtons(s)});return}}async respondWithAgentPicker(e){if(this.pickerAgents().length===0){await this.respondToInteraction(e,Bl,{content:"No agents available. Add existing, enabled agents to `allowed_agents` in the channel file.",flags:Ul});return}await this.respondToInteraction(e,Bl,{content:"Select an agent to chat with:",flags:Ul,components:this.buildAgentButtons(this.config.defaultAgent)})}buildAgentButtons(e){let t=this.pickerAgents().slice(0,25),s=[];for(let n=0;n<t.length;n+=5){let r=t.slice(n,n+5);s.push({type:1,components:r.map(i=>({type:2,style:i===e?1:2,label:i===e?`${i} \u2713`:i,custom_id:`switch:${i}`}))})}return s}async respondToInteraction(e,t,s){try{await this.discordApi("POST",`/interactions/${e.id}/${e.token}/callback`,{type:t,data:s})}catch(n){console.warn("Agent Fleet: Discord interaction response failed",n)}}async discordApi(e,t,s){let n=await(0,Br.requestUrl)({url:`${Ih}${t}`,method:e,contentType:"application/json",headers:{Authorization:`Bot ${this.credential.botToken}`,"User-Agent":Lh},...s!==void 0?{body:JSON.stringify(s)}:{},throw:!1});if(n.status===429){let r=n.json?.retry_after??Number(n.headers["retry-after"]??"1");return await new Promise(i=>window.setTimeout(i,Math.max(1e3,r*1e3))),this.discordApi(e,t,s)}if(n.status===401||n.status===403)throw new Error(`Discord ${e} ${t} ${n.status}: ${Yh(n.text)}`);if(n.status<200||n.status>=300)throw new Error(`Discord ${e} ${t} HTTP ${n.status}: ${n.text}`);if(n.status!==204)return n.json}async enqueueSend(e,t){let n=(this.sendQueues.get(e)??Promise.resolve()).then(t),r=n.catch(()=>{});this.sendQueues.set(e,r);try{await n}finally{this.sendQueues.get(e)===r&&this.sendQueues.delete(e)}}setStatus(e){if(this.status!==e){this.status=e;for(let t of this.statusHandlers)try{t(e)}catch{}}}};function $l(a,e){return a?`discord:${a}:${e}`:`discord:dm:${e}`}function jl(a){let e=a.split(":");return e[0]!=="discord"?null:e[2]??null}function Vh(a,e){let t=a.trimStart();if(e){let s=new RegExp(`^<@!?${e}>\\s*`);t=t.replace(s,"")}return t.trim()}function Yh(a){let e=a??"";try{let t=JSON.parse(e);if(t&&(t.message!==void 0||t.code!==void 0))return`${t.message??"error"} (code ${t.code??"?"})`}catch{}return e||"no body"}var on=require("obsidian");var Sa=class extends on.ItemView{constructor(t,s){super(t);this.plugin=s}getViewType(){return us}getDisplayText(){return"Agent Fleet"}getIcon(){return"bot"}async onOpen(){this.plugin.subscribeView(this),await this.render()}async onClose(){this.plugin.unsubscribeView(this)}async render(){let t=this.contentEl;t.empty(),t.addClass("af-sidebar");let s=this.plugin.runtime.getSnapshot(),n=this.plugin.runtime.getFleetStatus(),r=t.createDiv({cls:"af-sidebar-section"});r.createDiv({cls:"af-sidebar-section-header",text:"AGENT FLEET"});let i=[{icon:"layout-dashboard",label:"Dashboard",page:"dashboard"},{icon:"bot",label:"Agents",page:"agents",badge:()=>s.agents.length},{icon:"columns-3",label:"Tasks Board",page:"kanban"},{icon:"scroll-text",label:"Run History",page:"runs"},{icon:"shield-check",label:"Approvals",page:"approvals",badge:()=>n.pending},{icon:"puzzle",label:"Skills",page:"skills",badge:()=>s.skills.length},{icon:"plug",label:"MCP Servers",page:"mcp",badge:()=>this.plugin.repository.getMcpServers().length},{icon:"radio",label:"Channels",page:"channels",badge:()=>this.plugin.channelManager?.getConnectedCount()??s.channels.length}];for(let c of i){let d=r.createDiv({cls:"af-sidebar-nav-item"}),u=d.createSpan({cls:"af-sidebar-nav-icon"});(0,on.setIcon)(u,c.icon),d.createSpan({cls:"af-sidebar-nav-label",text:c.label});let h=c.badge?.();h!==void 0&&h>0&&d.createSpan({cls:"af-sidebar-badge",text:String(h)}),d.setAttribute("role","button"),d.setAttribute("tabindex","0"),d.onclick=()=>void this.plugin.navigateDashboard(c.page),d.onkeydown=p=>{(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),this.plugin.navigateDashboard(c.page))}}let o=t.createDiv({cls:"af-sidebar-section"});o.createDiv({cls:"af-sidebar-section-header",text:"AGENTS"}),s.agents.length===0&&o.createDiv({cls:"af-sidebar-empty",text:"No agents configured"});for(let c of s.agents){let d=this.plugin.runtime.getAgentState(c.name),u=o.createDiv({cls:"af-sidebar-agent-item"});u.createSpan({cls:`af-sidebar-agent-dot ${this.healthToClass(d.status)}`}),u.createSpan({cls:"af-sidebar-agent-name",text:c.name}),u.setAttribute("role","button"),u.setAttribute("tabindex","0"),u.onclick=()=>void this.plugin.navigateDashboard("agent-detail",c.name),u.onkeydown=h=>{(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),this.plugin.navigateDashboard("agent-detail",c.name))}}let l=t.createDiv({cls:"af-sidebar-section"});l.createDiv({cls:"af-sidebar-section-header",text:"QUICK ACTIONS"}),this.renderQuickAction(l,"plus","New Agent",()=>void this.plugin.createAgentTemplate()),this.renderQuickAction(l,"plus","New Task",()=>void this.plugin.openCreateTask()),this.renderQuickAction(l,"plus","New Skill",()=>void this.plugin.createSkillTemplate())}renderQuickAction(t,s,n,r){let i=t.createDiv({cls:"af-sidebar-action-item"}),o=i.createSpan({cls:"af-sidebar-action-icon"});(0,on.setIcon)(o,s),i.createSpan({text:n}),i.setAttribute("role","button"),i.setAttribute("tabindex","0"),i.onclick=r,i.onkeydown=l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),r())}}healthToClass(t){switch(t){case"running":return"running";case"error":return"error";case"pending":return"pending";case"disabled":return"disabled";default:return"idle"}}};var Z=require("obsidian");var Kh=[{match:/opus/i,rates:{input:15,output:75,cacheWrite:18.75,cacheRead:1.5}},{match:/sonnet/i,rates:{input:3,output:15,cacheWrite:3.75,cacheRead:.3}},{match:/haiku/i,rates:{input:1,output:5,cacheWrite:1.25,cacheRead:.1}},{match:/gpt-5|codex|o[0-9]/i,rates:{input:1.25,output:10,cacheWrite:1.25,cacheRead:.125}}],Jh={input:3,output:15,cacheWrite:3.75,cacheRead:.3};function Hl(a){for(let{match:e,rates:t}of Kh)if(e.test(a))return t;return Jh}function Wl(a,e){let t=Hl(a);return(e.inputTokens*t.input+e.outputTokens*t.output+e.cacheCreateTokens*t.cacheWrite+e.cacheReadTokens*t.cacheRead)/1e6}function ql(a,e){let t=Hl(a),s=.7*t.input+.3*t.output;return e*s/1e6}var zl=require("obsidian");function T(a,e,t){let s=a.createSpan({cls:t??"af-icon"});return(0,zl.setIcon)(s,e),s}function ot(a,e={}){let t=activeDocument.createElementNS("http://www.w3.org/2000/svg",a);for(let[s,n]of Object.entries(e))t.setAttribute(s,n);return t}function Xh(a){try{return new Date(a+"T12:00:00").toLocaleDateString(void 0,{month:"short",day:"numeric"})}catch{return a.slice(5)}}function Gl(a,e){let t=e.length||1,s=1e3,n=6,r=4,i=4,o=s-r-i-n*(t-1),l=Math.floor(o/t),c=140,d=36,u=18,h=u+c+d,p=Math.max(1,...e.map(f=>f.success+f.failure+f.cancelled)),m=ot("svg",{viewBox:`0 0 ${s} ${h}`,width:"100%",height:String(h),class:"af-chart-bar"});for(let f=0;f<=4;f++){let g=u+c-f/4*c;m.appendChild(ot("line",{x1:String(r),y1:String(g),x2:String(s-i),y2:String(g),stroke:"var(--af-text-faint)","stroke-opacity":"0.15","stroke-width":"1"}))}for(let f=0;f<e.length;f++){let g=e[f],w=r+f*(l+n),y=g.success+g.failure+g.cancelled,v=y/p*c,k=g.success/p*c,b=g.cancelled/p*c,P=g.failure/p*c;if(g.success>0&&m.appendChild(ot("rect",{x:String(w),y:String(u+c-k),width:String(l),height:String(Math.max(k,2)),fill:"var(--af-green)",opacity:"0.85"})),g.cancelled>0&&m.appendChild(ot("rect",{x:String(w),y:String(u+c-k-b),width:String(l),height:String(Math.max(b,2)),fill:"var(--af-yellow)",opacity:"0.85"})),g.failure>0&&m.appendChild(ot("rect",{x:String(w),y:String(u+c-v),width:String(l),height:String(Math.max(P,2)),fill:"var(--af-red)",opacity:"0.85"})),y===0&&m.appendChild(ot("rect",{x:String(w),y:String(u+c-3),width:String(l),height:"3",rx:"1.5",fill:"var(--af-text-faint)",opacity:"0.2"})),y>0){let M=ot("text",{x:String(w+l/2),y:String(u+c-v-5),"text-anchor":"middle","font-size":"10","font-weight":"600",fill:"var(--af-text-secondary)"});M.textContent=String(y),m.appendChild(M)}let A=ot("text",{x:String(w+l/2),y:String(u+c+16),"text-anchor":"middle","font-size":"10",fill:"var(--af-text-muted)"});A.textContent=Xh(g.date),m.appendChild(A)}a.appendChild(m)}function Vl(a,e,t){let l=2*Math.PI*46,c=t>0?e/t:0,d=l*c,u=l-d,h=ot("svg",{viewBox:"0 0 130 130",width:String(130),height:String(130),class:"af-chart-donut"});h.appendChild(ot("circle",{cx:String(65),cy:String(65),r:String(46),fill:"none",stroke:t>0?"var(--af-red)":"var(--af-text-faint)","stroke-width":String(12),opacity:"0.2"})),c>0&&h.appendChild(ot("circle",{cx:String(65),cy:String(65),r:String(46),fill:"none",stroke:"var(--af-green)","stroke-width":String(12),"stroke-dasharray":`${d} ${u}`,"stroke-dashoffset":String(l*.25),"stroke-linecap":"round"}));let p=ot("text",{x:String(65),y:String(61),"text-anchor":"middle","dominant-baseline":"middle","font-size":"24","font-weight":"700",fill:"var(--af-text-primary)"});p.textContent=`${Math.round(c*100)}%`,h.appendChild(p);let m=ot("text",{x:String(65),y:String(83),"text-anchor":"middle","font-size":"10",fill:"var(--af-text-muted)"});m.textContent=`${e}/${t} runs`,h.appendChild(m),a.appendChild(h)}function Yl(a,e){a.draggable=!0,a.addEventListener("dragstart",t=>{t.dataTransfer?.setData("text/plain",e),a.addClass("af-dragging")}),a.addEventListener("dragend",()=>{a.removeClass("af-dragging")})}function Kl(a,e){a.addEventListener("dragover",t=>{t.preventDefault(),a.addClass("af-drag-over")}),a.addEventListener("dragleave",t=>{let s=t.relatedTarget;(!s||!a.contains(s))&&a.removeClass("af-drag-over")}),a.addEventListener("drop",t=>{t.preventDefault();let s=t.dataTransfer?.getData("text/plain");a.removeClass("af-drag-over"),s&&e(s)})}var Fe=require("obsidian");function Ur(a){switch(a){case"connected":return"idle";case"connecting":case"reconnecting":return"pending";case"needs-auth":case"error":return"error";case"stopped":case"disabled":default:return"disabled"}}function $r(a,e,t){let{plugin:s}=e,n=s.runtime.getSnapshot(),r=s.channelCredentials.list(),i=a.createDiv({cls:"af-detail-header"}),o=i.createDiv({cls:"af-detail-header-left"});if(t){let S=s.channelManager?.getChannelStatus(t.name)??"disabled",j=o.createDiv({cls:`af-agent-card-avatar ${Ur(S)}`});(0,Fe.setIcon)(j,"radio");let ce=o.createDiv();ce.createDiv({cls:"af-detail-header-name",text:`Edit Channel: ${t.name}`}),ce.createDiv({cls:"af-detail-header-desc",text:`Status: ${S}`})}else{let S=o.createDiv({cls:"af-agent-card-avatar idle"});(0,Fe.setIcon)(S,"plus");let j=o.createDiv();j.createDiv({cls:"af-detail-header-name",text:"Create New Channel"}),j.createDiv({cls:"af-detail-header-desc",text:"Connect an external chat transport to an agent"})}i.createDiv({cls:"af-detail-header-actions"});let l={name:"",type:t?t.type:"slack",defaultAgent:t?t.defaultAgent:n.agents[0]?.name??"",allowedAgents:t?[...t.allowedAgents]:[],credentialRef:t?t.credentialRef:r[0]?.ref??"",allowedUsers:t?t.allowedUsers.join(`
|
|
11940
|
+
`):"",perUserSessions:t?t.perUserSessions:!0,channelContext:t?t.channelContext:"",enabled:t?t.enabled:!0,tags:t?t.tags.join(", "):"",body:t?t.body:"",transportJson:t&&Object.keys(t.transport).length>0?JSON.stringify(t.transport,null,2):""},c=a.createDiv({cls:"af-create-form"}),d=c.createDiv({cls:"af-create-section"}),u=d.createDiv({cls:"af-create-section-header"}),h=u.createSpan({cls:"af-create-section-icon"});if((0,Fe.setIcon)(h,"radio"),u.createSpan({text:"Channel Details"}),t){let S=d.createDiv({cls:"af-form-row"});S.createDiv({cls:"af-form-label",text:"Name"}),S.createEl("input",{cls:"af-form-input",attr:{type:"text",value:t.name,disabled:"true"}}).setCssStyles({opacity:"0.6"})}else e.createFormField(d,"Name","my-slack","Unique identifier for this channel",S=>{l.name=S});let p=d.createDiv({cls:"af-form-row"});p.createDiv({cls:"af-form-label",text:"Type"});let m=p.createEl("select",{cls:"af-form-select"});for(let S of["slack","telegram","discord"]){let j=m.createEl("option",{text:S,attr:{value:S}});t&&S===t.type&&(j.selected=!0)}m.addEventListener("change",()=>{l.type=m.value});let f=d.createDiv({cls:"af-form-row"}),g=f.createDiv({cls:"af-form-label"});g.setText("Credential"),e.addTooltip(g,"Configured in Settings \u2192 Agent Fleet \u2192 Channel Credentials");let w=f.createEl("select",{cls:"af-form-select"});r.length===0&&w.createEl("option",{text:"(no credentials configured)",attr:{value:""}});for(let S of r){let j=w.createEl("option",{text:`${S.ref} (${S.entry.type})`,attr:{value:S.ref}});t&&S.ref===t.credentialRef&&(j.selected=!0)}w.addEventListener("change",()=>{l.credentialRef=w.value});let y=d.createDiv({cls:"af-form-row af-form-row-toggle"});y.createDiv({cls:"af-form-label",text:"Enabled"});let v=y.createDiv({cls:`af-agent-card-toggle${l.enabled?" on":""}`});v.onclick=()=>{let S=v.hasClass("on");v.toggleClass("on",!S),l.enabled=!S};let k=c.createDiv({cls:"af-create-section"}),b=k.createDiv({cls:"af-create-section-header"}),P=b.createSpan({cls:"af-create-section-icon"});(0,Fe.setIcon)(P,"bot"),b.createSpan({text:"Agent Routing"});let A=k.createDiv({cls:"af-form-row"}),M=A.createDiv({cls:"af-form-label"});M.setText("Default agent"),e.addTooltip(M,"Used when no @agent-name prefix is given in a message");let E=A.createEl("select",{cls:"af-form-select"});for(let S of n.agents){let j=E.createEl("option",{text:S.name,attr:{value:S.name}});t&&S.name===t.defaultAgent&&(j.selected=!0)}E.addEventListener("change",()=>{l.defaultAgent=E.value});let x=k.createDiv({cls:"af-form-row"}),_=x.createDiv({cls:"af-form-label"});_.setText("Allowed agents"),e.addTooltip(_,"Agents reachable via @prefix. Leave unchecked to allow all agents.");let R=x.createDiv({cls:"af-form-checkboxes"});for(let S of n.agents){let j=R.createEl("label",{cls:"af-form-checkbox-label"}),ce=j.createEl("input",{attr:{type:"checkbox",value:S.name}});t&&t.allowedAgents.includes(S.name)&&(ce.checked=!0),j.appendText(` ${S.name}`),ce.addEventListener("change",()=>{ce.checked?l.allowedAgents.includes(S.name)||l.allowedAgents.push(S.name):l.allowedAgents=l.allowedAgents.filter(Se=>Se!==S.name)})}let O=k.createDiv({cls:"af-form-row af-form-row-toggle"}),F=O.createDiv({cls:"af-form-label"});F.setText("Per-user sessions"),e.addTooltip(F,"Each external user gets their own isolated Claude session");let B=O.createDiv({cls:`af-agent-card-toggle${l.perUserSessions?" on":""}`});B.onclick=()=>{let S=B.hasClass("on");B.toggleClass("on",!S),l.perUserSessions=!S};let q=c.createDiv({cls:"af-create-section"}),oe=q.createDiv({cls:"af-create-section-header"}),be=oe.createSpan({cls:"af-create-section-icon"});(0,Fe.setIcon)(be,"shield-check"),oe.createSpan({text:"Access Control"});let ne=q.createDiv({cls:"af-form-label"});ne.setText("Allowed users"),e.addTooltip(ne,t?"Slack user IDs (U...), one per line. Only listed users can reach the bot.":"User IDs, one per line \u2014 Slack (U...), Telegram (numeric), or Discord (numeric snowflakes). Only listed users can reach the bot.");let Y=q.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`U0AQW6P37N1
|
|
11941
|
+
U0BXYZ12345`,rows:"4"}});t&&(Y.value=t.allowedUsers.join(`
|
|
11942
|
+
`)),Y.addEventListener("input",()=>{l.allowedUsers=Y.value});let H=c.createDiv({cls:"af-create-section"}),X=H.createDiv({cls:"af-create-section-header"}),me=X.createSpan({cls:"af-create-section-icon"});(0,Fe.setIcon)(me,"message-square");let ee=X.createSpan({text:"Channel Context"});e.addTooltip(ee,"Extra instructions appended to the agent's system prompt when reached through this channel");let J=H.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"You are being contacted via Slack. Keep replies concise...",rows:"6"}});t&&(J.value=t.channelContext),J.addEventListener("input",()=>{l.channelContext=J.value}),e.createFormField(d,"Tags","ops, internal","Comma-separated metadata",S=>{l.tags=S},t?t.tags.join(", "):void 0);let K=c.createDiv({cls:"af-create-section"}),ke=K.createDiv({cls:"af-create-section-header"}),je=ke.createSpan({cls:"af-create-section-icon"});(0,Fe.setIcon)(je,"settings");let Qe=ke.createSpan({text:"Advanced"});e.addTooltip(Qe,"Markdown body (shown in the channel detail page) and transport-specific overrides");let Ze=K.createDiv({cls:"af-form-label"});Ze.setText("Body (markdown)"),t||e.addTooltip(Ze,"Free-form notes for this channel. Shown in the channel detail page; not sent to the agent.");let He=K.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Notes, runbook snippets, escalation contacts\u2026",rows:"4"}});t&&(He.value=t.body),He.addEventListener("input",()=>{l.body=He.value});let $=K.createDiv({cls:"af-form-label"});$.setText("Transport config (JSON)"),e.addTooltip($,t?"Optional JSON object for transport-specific overrides (e.g. Slack socket_mode). Leave blank for defaults.":"Optional JSON object for transport-specific overrides (e.g. Slack socket_mode, telegram webhook settings). Leave blank for defaults.");let ae=K.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`{
|
|
11957
11943
|
"socket_mode": true
|
|
11958
|
-
}`,rows:"4"}});Ce.value=m.transportJson,Ce.addEventListener("input",()=>{m.transportJson=Ce.value});let xe=s.createDiv({cls:"af-create-footer"}),he=xe.createEl("button",{cls:"af-btn-sm danger"});R(he,"trash-2","af-btn-icon"),he.appendText(" Delete"),he.onclick=async()=>{await this.plugin.repository.deleteChannel(a.name),new b.Notice(`Channel "${a.name}" deleted.`),await new Promise(I=>window.setTimeout(I,200)),await this.plugin.refreshFromVault(),this.navigate("channels")},xe.createDiv({cls:"af-toolbar-spacer"});let $e=xe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});$e.onclick=()=>this.navigate("channels");let ie=xe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(ie,"check","af-btn-icon"),ie.appendText(" Save Changes"),ie.onclick=async()=>{let I=te=>te.split(/[\n,]+/).map(st=>st.trim()).filter(Boolean),se=te=>te.split(",").map(st=>st.trim()).filter(Boolean),ce;if(m.transportJson.trim())try{let te=JSON.parse(m.transportJson);if(te&&typeof te=="object"&&!Array.isArray(te))ce=te;else{new b.Notice("Transport config must be a JSON object.");return}}catch(te){new b.Notice(`Transport JSON is invalid: ${te instanceof Error?te.message:String(te)}`);return}else ce={};try{await this.plugin.repository.updateChannel(a.name,{type:m.type,default_agent:m.defaultAgent,allowed_agents:m.allowedAgents.length>0?m.allowedAgents:[],enabled:m.enabled,credential_ref:m.credentialRef,allowed_users:I(m.allowedUsers),per_user_sessions:m.perUserSessions,channel_context:m.channelContext.trim(),tags:se(m.tags),body:m.body.trim(),transport:ce}),new b.Notice(`Channel "${a.name}" updated.`),await this.plugin.refreshFromVault(),this.navigate("channels")}catch(te){let st=te instanceof Error?te.message:String(te);new b.Notice(`Failed to update channel: ${st}`)}}}renderApprovalsPage(e){let s=e.createDiv({cls:"af-approvals-page"}),n=this.plugin.runtime.getRecentRuns(),a=s.createDiv({cls:"af-agents-toolbar"});a.createDiv({cls:"af-page-title",text:"Approvals"}),a.createDiv({cls:"af-toolbar-spacer"});let i=n.filter(c=>(c.approvals??[]).some(l=>l.status==="pending"));if(i.length>0){let c=s.createDiv({cls:"af-section-card"}),h=c.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(h,"alert-triangle"),h.appendText(` Pending (${i.length})`);let d=c.createDiv({cls:"af-approvals-list"});for(let u of i)this.renderApprovalItem(d,u,!0)}else{let c=s.createDiv({cls:"af-section-card"});this.renderEmptyState(c,"shield-check","No pending approvals","All clear!")}let o=n.filter(c=>(c.approvals??[]).some(l=>l.status!=="pending"));if(o.length>0){let c=s.createDiv({cls:"af-section-card"}),h=c.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(h,"check-circle-2"),h.appendText(" History");let d=c.createDiv({cls:"af-approvals-list"});for(let u of o.slice(0,20))this.renderApprovalItem(d,u,!1)}}renderApprovalItem(e,s,n){for(let a of s.approvals??[]){if(n&&a.status!=="pending"||!n&&a.status==="pending")continue;let i=e.createDiv({cls:"af-approval-item"}),o=i.createDiv({cls:"af-approval-item-icon"});a.status==="pending"?((0,b.setIcon)(o,"shield-check"),o.addClass("pending")):a.status==="approved"?((0,b.setIcon)(o,"check-circle-2"),o.addClass("approved")):((0,b.setIcon)(o,"x-circle"),o.addClass("rejected"));let c=i.createDiv({cls:"af-approval-item-body"});if(c.createDiv({cls:"af-approval-item-title",text:`${s.agent} \u2192 ${a.tool}`}),c.createDiv({cls:"af-approval-item-meta",text:`Task: ${s.task} \xB7 ${a.command??"no command"} \xB7 ${this.formatStarted(s.started)}`}),a.reason&&c.createDiv({cls:"af-approval-item-reason",text:`Reason: ${a.reason}`}),n&&a.status==="pending"){let l=i.createDiv({cls:"af-approval-item-actions"}),h=l.createEl("button",{cls:"af-btn-approve"});R(h,"check-circle-2","af-btn-icon"),h.appendText(" Approve"),h.onclick=()=>void this.plugin.runtime.resolveApproval(s,a.tool,"approved").then(()=>this.render());let d=l.createEl("button",{cls:"af-btn-reject"});R(d,"x-circle","af-btn-icon"),d.appendText(" Reject"),d.onclick=()=>void this.plugin.runtime.resolveApproval(s,a.tool,"rejected").then(()=>this.render())}}}renderTaskDetailPage(e){let s=e.createDiv({cls:"af-task-detail-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"circle-dot","No task selected","");return}let a=this.plugin.runtime.getSnapshot().tasks.find(P=>P.taskId===n);if(!a){this.renderEmptyState(s,"circle-dot","Task not found",`Task "${n}" was not found`);return}let i=this.plugin.runtime.getSnapshot(),o=this.plugin.runtime.getRecentRuns().filter(P=>P.task===n),c=i.agents.find(P=>P.name===a.agent),l=s.createDiv({cls:"af-detail-header"}),h=l.createDiv({cls:"af-detail-header-left"}),d=h.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(d,"circle-dot");let u=h.createDiv();u.createDiv({cls:"af-detail-header-name",text:a.taskId}),u.createDiv({cls:"af-detail-header-desc",text:`Agent: ${a.agent}`});let p=l.createDiv({cls:"af-detail-header-actions"}),m=p.createEl("button",{cls:"af-btn-sm"});R(m,"edit","af-btn-icon"),m.appendText(" Edit"),m.onclick=()=>this.navigate("edit-task",a.taskId);let f=p.createEl("button",{cls:"af-btn-sm primary"});R(f,"play","af-btn-icon"),f.appendText(" Run Now"),f.onclick=()=>void this.plugin.runtime.runTaskNow(a);let g=s.createDiv({cls:"af-section-card"}),v=g.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(v,"file-text"),v.appendText(" Details");let k=g.createDiv({cls:"af-config-form"});this.renderConfigRow(k,"Agent",a.agent),this.renderConfigRow(k,"Priority",a.priority.charAt(0).toUpperCase()+a.priority.slice(1)),this.renderConfigRow(k,"Status",a.enabled?"Enabled":"Disabled");let w=a.schedule?this.humanizeCron(a.schedule):a.runAt??"Manual (run on demand)";this.renderConfigRow(k,"Schedule",w),a.schedule&&this.renderConfigRow(k,"Catch up if missed",a.catchUp?"Yes":"No"),this.renderConfigRow(k,"Created",a.created),this.renderConfigRow(k,"Runs",String(a.runCount)),a.lastRun&&this.renderConfigRow(k,"Last Run",this.formatStarted(a.lastRun));let S=s.createDiv({cls:"af-section-card"}),_=S.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(_,"message-square"),_.appendText(" Instructions"),S.createDiv({cls:"af-output-block",text:a.body||"(empty)"});let D=s.createDiv({cls:"af-section-card"}),C=D.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});R(C,"scroll-text"),C.appendText(" Recent Runs");let E=D.createDiv({cls:"af-timeline"});if(o.length===0)this.renderEmptyState(E,"scroll-text","No runs yet","");else for(let P of o.slice(0,10))this.renderTimelineItem(E,P)}handleSearch(e,s){if(s.querySelector(".af-search-results")?.remove(),e.length<2)return;let n=e.toLowerCase(),a=this.plugin.runtime.getSnapshot(),i=this.plugin.runtime.getRecentRuns(),o=[];for(let l of a.agents)(l.name.toLowerCase().includes(n)||(l.description?.toLowerCase().includes(n)??!1))&&o.push({label:`Agent: ${l.name}`,icon:"bot",action:()=>this.navigate("agent-detail",l.name)});for(let l of a.tasks)(l.taskId.toLowerCase().includes(n)||l.body.toLowerCase().includes(n))&&o.push({label:`Task: ${l.taskId}`,icon:"circle-dot",action:()=>this.navigate("task-detail",l.taskId)});for(let l of a.skills)l.name.toLowerCase().includes(n)&&o.push({label:`Skill: ${l.name}`,icon:"puzzle",action:()=>this.navigate("edit-skill",l.name)});for(let l of i.slice(0,20))l.output.toLowerCase().includes(n)&&o.push({label:`Run: ${l.agent} / ${l.task}`,icon:"scroll-text",action:()=>this.openSlideover(l)});if(o.length===0)return;let c=s.createDiv({cls:"af-search-results"});for(let l of o.slice(0,10)){let h=c.createDiv({cls:"af-search-result-item"});R(h,l.icon,"af-search-result-icon"),h.createSpan({text:l.label}),h.onclick=()=>{c.remove(),l.action()}}}openChatSlideover(e){this.plugin.openChatView(e.name)}openSlideover(e){this.contentEl.querySelector(".af-slideover-overlay")?.remove();let s=this.contentEl.createDiv({cls:"af-slideover-overlay"}),n=s.createDiv({cls:"af-slideover"}),a=n.createDiv({cls:"af-slideover-header"});a.createDiv({cls:"af-slideover-title",text:"Run Details"});let i=a.createEl("button",{cls:"clickable-icon"});(0,b.setIcon)(i,"cross"),i.onclick=()=>s.remove();let o=n.createDiv({cls:"af-slideover-body"}),c=o.createDiv({cls:"af-slideover-section"});c.createDiv({cls:"af-slideover-section-title",text:"METADATA"}),this.renderDetailRow(c,"Run ID",e.runId.slice(0,8)),this.renderDetailRow(c,"Agent",e.agent),this.renderDetailRow(c,"Task",e.task);let l=c.createDiv({cls:"af-detail-row"});l.createSpan({cls:"af-detail-label",text:"Status"});let d=l.createSpan({cls:"af-detail-value"}).createSpan({cls:`af-status-badge ${this.statusToBadgeClass(e.status)}`}),u=d.createSpan();(0,b.setIcon)(u,this.statusToIconName(e.status)),d.appendText(` ${this.statusToBadgeText(e.status)}`),this.renderDetailRow(c,"Started",e.started),this.renderDetailRow(c,"Duration",this.formatDuration(e.durationSeconds)),this.renderDetailRow(c,"Tokens",e.tokensUsed?e.tokensUsed.toLocaleString():"\u2014");{let w={task:"from task override",agent:"from agent",settings:"from settings default","cli-default":"CLI default"},S=e.modelSource?` (${w[e.modelSource]??e.modelSource})`:"",T=e.concreteModel&&e.concreteModel!==e.model?` \u2192 ${e.concreteModel}`:"";this.renderDetailRow(c,"Model",`${e.model}${T}${S}`)}let p=5e4,m=w=>w.length>p?w.slice(0,p)+`
|
|
11959
|
-
|
|
11960
|
-
---
|
|
11961
|
-
*Truncated (${(w.length/1024).toFixed(0)} KB total). Open the run note for full content.*`:w,f=!!(e.finalResult&&e.finalResult.trim()),g=e.output?.trim()??"",y=f&&g.length>0&&g!==e.finalResult.trim();if(f){let w=o.createDiv({cls:"af-slideover-section"});w.createDiv({cls:"af-slideover-section-title",text:"OUTPUT"});let S=w.createDiv({cls:"af-output-block af-compact-md"});if(b.MarkdownRenderer.render(this.app,m(e.finalResult),S,"",this),y){let T=w.createEl("details",{cls:"af-run-transcript"}),_=T.createEl("summary");(0,b.setIcon)(_.createSpan({cls:"af-run-transcript-icon"}),"file-text"),_.createSpan({text:"Show full transcript"}),_.createSpan({cls:"af-run-transcript-meta"}).setText(`${(g.length/1024).toFixed(1)} KB`);let O=T.createDiv({cls:"af-output-block af-compact-md af-run-transcript-body"});b.MarkdownRenderer.render(this.app,m(g),O,"",this)}}else if(g){let w=o.createDiv({cls:"af-slideover-section"});w.createDiv({cls:"af-slideover-section-title",text:"OUTPUT"});let S=w.createDiv({cls:"af-output-block af-compact-md"});b.MarkdownRenderer.render(this.app,m(g),S,"",this)}if(e.toolsUsed.length>0){let w=o.createDiv({cls:"af-slideover-section"});w.createDiv({cls:"af-slideover-section-title",text:"TOOLS USED"}),w.createDiv({cls:"af-output-block",text:e.toolsUsed.join(`
|
|
11962
|
-
`)})}let v=o.createDiv({cls:"af-slideover-actions"});if(e.filePath){let w=v.createEl("button",{cls:"af-btn-sm"});R(w,"external-link","af-btn-icon"),w.appendText(" Open Run Note"),w.onclick=()=>void this.plugin.openPath(e.filePath)}let k=v.createEl("button",{cls:"af-btn-sm primary"});R(k,"refresh-cw","af-btn-icon"),k.appendText(" Re-run Task"),k.onclick=()=>void this.plugin.runAgentPrompt(e.agent),s.onclick=w=>{w.target===s&&s.remove()}}renderDetailRow(e,s,n){let a=e.createDiv({cls:"af-detail-row"});a.createSpan({cls:"af-detail-label",text:s}),a.createSpan({cls:"af-detail-value af-mono",text:n})}renderEmptyState(e,s,n,a){let i=e.createDiv({cls:"af-empty-state"}),o=i.createDiv({cls:"af-empty-icon"});(0,b.setIcon)(o,s),i.createDiv({cls:"af-empty-label",text:n}),a&&i.createDiv({cls:"af-empty-sublabel",text:a})}healthToClass(e){switch(e){case"running":return"running";case"error":return"error";case"pending":return"pending";case"disabled":return"disabled";default:return"idle"}}statusToTimelineClass(e){switch(e){case"success":return"success";case"failure":case"timeout":return"error";case"cancelled":return"warning";case"pending_approval":return"pending";default:return"running"}}statusToIconName(e){switch(e){case"success":return"check-circle-2";case"failure":return"x-circle";case"timeout":return"clock";case"pending_approval":return"shield-check";case"cancelled":return"square";default:return"loader-2"}}statusToBadgeClass(e){switch(e){case"success":return"success";case"failure":return"failure";case"timeout":return"timeout";case"pending_approval":return"pending";case"cancelled":return"cancelled";default:return"running"}}statusToBadgeText(e){switch(e){case"success":return"Success";case"failure":return"Failed";case"timeout":return"Timeout";case"pending_approval":return"Pending";case"cancelled":return"Cancelled";case"interrupted":return"Interrupted";default:return e}}formatDuration(e){if(e<60)return`${e}s`;let s=Math.floor(e/60),n=e%60;return n>0?`${s}m ${n}s`:`${s}m`}formatStarted(e){try{let s=new Date(e),n=new Date;if(s.toDateString()===n.toDateString())return s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let a=new Date(n);return a.setDate(a.getDate()-1),s.toDateString()===a.toDateString()?`Yesterday ${s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`:s.toLocaleDateString([],{month:"short",day:"numeric"})+` ${s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`}catch{return e}}formatNextRun(e){try{let s=new Date(e),n=new Date,a=s.getTime()-n.getTime();if(a<0)return"overdue";let i=Math.round(a/6e4);if(i<60)return`${i}m`;let o=Math.round(i/60);return o<24?`${o}h`:s.toLocaleDateString([],{month:"short",day:"numeric"})}catch{return e}}getNextTaskLabel(e){let n=e.map(i=>i.nextRun).filter(Boolean).sort()[0];return n?`${e.find(i=>i.nextRun===n)?.agent??"unknown"} in ${this.formatNextRun(n)}`:"none"}getInitials(e){return e.split("-").map(s=>s[0]?.toUpperCase()??"").slice(0,2).join("")}renderAgentAvatar(e,s){let n=s.avatar?.trim();if(!n){(0,b.setIcon)(e,"bot");return}/^[a-z][a-z0-9-]*$/.test(n)?(0,b.setIcon)(e,n):e.setText(n)}getSkillIcon(e){return e.includes("git")?"settings":e.includes("summarize")||e.includes("log")?"activity":e.includes("review")||e.includes("check")?"check-circle-2":e.includes("vault")||e.includes("note")?"file-text":"puzzle"}renderInlineSchedule(e,s){let n=this.parseCronComponents(s.schedule),a=e.createDiv({cls:"af-form-row"});a.createDiv({cls:"af-form-label",text:"Frequency"});let i=a.createEl("select",{cls:"af-form-select"}),o=[["every_5m","Every 5 minutes"],["every_15m","Every 15 minutes"],["every_30m","Every 30 minutes"],["every_hour","Every hour"],["every_2h","Every 2 hours"],["daily","Daily"],["weekdays","Weekdays"],["weekly","Weekly"],["monthly","Monthly"]];for(let[w,S]of o){let T=i.createEl("option",{text:S,attr:{value:w}});w===n.freq&&(T.selected=!0)}let c=e.createDiv({cls:"af-form-row af-schedule-time-row"});c.createDiv({cls:"af-form-label",text:"Time"});let l=c.createDiv({cls:"af-schedule-time-selects"}),h=l.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let w=0;w<24;w++){let S=w>=12?"PM":"AM",T=w===0?12:w>12?w-12:w,_=h.createEl("option",{text:`${T} ${S}`,attr:{value:String(w)}});w===n.hour&&(_.selected=!0)}l.createSpan({cls:"af-schedule-colon",text:":"});let d=l.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let w=0;w<60;w+=5){let S=d.createEl("option",{text:String(w).padStart(2,"0"),attr:{value:String(w)}});w===n.minute&&(S.selected=!0)}let u=e.createDiv({cls:"af-form-row af-schedule-day-row"});u.createDiv({cls:"af-form-label",text:"Day"});let p=u.createDiv({cls:"af-schedule-day-buttons"}),m=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],f=new Set(n.days);for(let w=0;w<7;w++){let S=p.createEl("button",{cls:`af-schedule-day-btn${f.has(w)?" active":""}`,text:m[w]});S.onclick=()=>{f.has(w)?f.delete(w):f.add(w),S.toggleClass("active",f.has(w)),k()}}let g=e.createDiv({cls:"af-form-row af-schedule-dom-row"});g.createDiv({cls:"af-form-label",text:"Day of month"});let y=g.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let w=1;w<=28;w++){let S=y.createEl("option",{text:String(w),attr:{value:String(w)}});w===n.dayOfMonth&&(S.selected=!0)}let v=()=>{let w=i.value,S=["daily","weekdays","weekly","monthly"].includes(w),T=w==="weekly",_=w==="monthly";c.setCssStyles({display:S?"":"none"}),u.setCssStyles({display:T?"":"none"}),g.setCssStyles({display:_?"":"none"})},k=()=>{let w=i.value,S=h.value,T=d.value,_="";switch(w){case"every_5m":_="*/5 * * * *";break;case"every_15m":_="*/15 * * * *";break;case"every_30m":_="*/30 * * * *";break;case"every_hour":_="0 * * * *";break;case"every_2h":_="0 */2 * * *";break;case"daily":_=`${T} ${S} * * *`;break;case"weekdays":_=`${T} ${S} * * 1-5`;break;case"weekly":{let D=Array.from(f).sort().join(",")||"1";_=`${T} ${S} * * ${D}`;break}case"monthly":_=`${T} ${S} ${y.value} * *`;break}s.schedule=_,s.type="recurring"};i.addEventListener("change",()=>{v(),k()}),h.addEventListener("change",k),d.addEventListener("change",k),y.addEventListener("change",k),v()}renderHeartbeatSchedule(e,s){let n=this.parseCronComponents(s.heartbeatSchedule),a=e.createDiv({cls:"af-form-row"});a.createDiv({cls:"af-form-label",text:"Frequency"});let i=a.createEl("select",{cls:"af-form-select"}),o=[["every_5m","Every 5 minutes"],["every_15m","Every 15 minutes"],["every_30m","Every 30 minutes"],["every_hour","Every hour"],["every_2h","Every 2 hours"],["every_4h","Every 4 hours"],["every_6h","Every 6 hours"],["every_12h","Every 12 hours"],["daily","Once a day"]],c="every_hour",l={"*/5 * * * *":"every_5m","*/15 * * * *":"every_15m","*/30 * * * *":"every_30m","0 * * * *":"every_hour","0 */2 * * *":"every_2h","0 */4 * * *":"every_4h","0 */6 * * *":"every_6h","0 */12 * * *":"every_12h"};l[s.heartbeatSchedule]?c=l[s.heartbeatSchedule]:(n.freq==="daily"||n.freq==="weekdays")&&(c="daily");for(let[g,y]of o){let v=i.createEl("option",{text:y,attr:{value:g}});g===c&&(v.selected=!0)}let h=e.createDiv({cls:"af-form-row af-schedule-time-row"});h.createDiv({cls:"af-form-label",text:"Time"});let d=h.createDiv({cls:"af-schedule-time-selects"}),u=d.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let g=0;g<24;g++){let y=g>=12?"PM":"AM",v=g===0?12:g>12?g-12:g,k=u.createEl("option",{text:`${v} ${y}`,attr:{value:String(g)}});g===n.hour&&(k.selected=!0)}d.createSpan({cls:"af-schedule-colon",text:":"});let p=d.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let g=0;g<60;g+=5){let y=p.createEl("option",{text:String(g).padStart(2,"0"),attr:{value:String(g)}});g===n.minute&&(y.selected=!0)}let m=()=>{h.setCssStyles({display:i.value==="daily"?"":"none"})},f=()=>{let g=i.value,y=u.value,v=p.value;switch(g){case"every_5m":s.heartbeatSchedule="*/5 * * * *";break;case"every_15m":s.heartbeatSchedule="*/15 * * * *";break;case"every_30m":s.heartbeatSchedule="*/30 * * * *";break;case"every_hour":s.heartbeatSchedule="0 * * * *";break;case"every_2h":s.heartbeatSchedule="0 */2 * * *";break;case"every_4h":s.heartbeatSchedule="0 */4 * * *";break;case"every_6h":s.heartbeatSchedule="0 */6 * * *";break;case"every_12h":s.heartbeatSchedule="0 */12 * * *";break;case"daily":s.heartbeatSchedule=`${v} ${y} * * *`;break}};i.addEventListener("change",()=>{m(),f()}),u.addEventListener("change",f),p.addEventListener("change",f),m()}parseCronComponents(e){let s={freq:"daily",hour:9,minute:0,days:[1],dayOfMonth:1};if(!e?.trim())return s;let n={"*/5 * * * *":"every_5m","*/15 * * * *":"every_15m","*/30 * * * *":"every_30m","0 * * * *":"every_hour","0 */2 * * *":"every_2h"};if(n[e])return{...s,freq:n[e]};let a=e.trim().split(/\s+/);if(a.length!==5)return s;let[i,o,c,,l]=a,h=parseInt(o??"9",10),d=parseInt(i??"0",10);if(c==="*"&&l==="*")return{...s,freq:"daily",hour:h,minute:d};if(c==="*"&&l==="1-5")return{...s,freq:"weekdays",hour:h,minute:d};if(c==="*"&&l!=="*"){let u=(l??"1").split(",").map(p=>parseInt(p,10));return{...s,freq:"weekly",hour:h,minute:d,days:u}}return l==="*"&&c!=="*"?{...s,freq:"monthly",hour:h,minute:d,dayOfMonth:parseInt(c??"1",10)}:{...s,hour:h,minute:d}}humanizeCron(e){let s={"*/5 * * * *":"Every 5 minutes","*/10 * * * *":"Every 10 minutes","*/15 * * * *":"Every 15 minutes","*/30 * * * *":"Every 30 minutes","0 * * * *":"Every hour","0 */2 * * *":"Every 2 hours"};if(s[e])return s[e];let n=e.toLowerCase().trim();if(n.startsWith("every ")||n.startsWith("daily ")||n==="daily")return e;if(n.startsWith("hourly"))return"Every hour";if(n.startsWith("weekdays")||n.startsWith("weekly")||n.startsWith("monthly"))return e;let a=e.trim().split(/\s+/);if(a.length!==5)return e;let[i,o,c,,l]=a,h=(p,m)=>{let f=parseInt(p??"0",10),g=parseInt(m??"0",10),y=f>=12?"PM":"AM",v=f===0?12:f>12?f-12:f;return g===0?`${v} ${y}`:`${v}:${String(g).padStart(2,"0")} ${y}`},d=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],u=p=>p==="1-5"?"weekdays":p==="0,6"?"weekends":p.split(",").map(f=>parseInt(f,10)).map(f=>d[f]??f).join(", ");return o==="*"&&c==="*"&&l==="*"?i==="*"?"Every minute":`Every hour at :${String(i).padStart(2,"0")}`:c==="*"&&l==="*"&&o!=="*"?`Daily at ${h(o??"0",i??"0")}`:c==="*"&&l==="1-5"&&o!=="*"?`Weekdays at ${h(o??"0",i??"0")}`:c==="*"&&l!=="*"&&o!=="*"?`${u(l??"1")} at ${h(o??"0",i??"0")}`:l==="*"&&c!=="*"&&o!=="*"?`Monthly on the ${c} at ${h(o??"0",i??"0")}`:e}getTagClass(e){return e==="monitoring"?"monitoring":e==="devops"?"devops":e==="sample"?"sample":"default"}renderCreateAgentPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=s.createDiv({cls:"af-detail-header"}),a=n.createDiv({cls:"af-detail-header-left"}),i=a.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(i,"plus");let o=a.createDiv();o.createDiv({cls:"af-detail-header-name",text:"Create New Agent"}),o.createDiv({cls:"af-detail-header-desc",text:"Configure a new agent for your fleet"});let c=n.createDiv({cls:"af-detail-header-actions"}),l={name:"",description:"",avatar:"",tags:"",systemPrompt:"",model:"default",adapter:"claude-code",cwd:"",timeout:300,permissionMode:"bypassPermissions",effort:"",selectedSkills:new Set,selectedMcpServers:new Set,skillsBody:"",contextBody:"",approvalRequired:"",memory:!0,enabled:!0,allowedCommands:"",blockedCommands:"",heartbeatEnabled:!1,heartbeatSchedule:"0 */6 * * *",heartbeatBody:"",heartbeatNotify:!0,heartbeatChannel:"",heartbeatChannelTarget:"",autoCompactThreshold:85,wikiReferences:[]},h={none:{label:"None",prompt:""},coding:{label:"Coding Agent",prompt:`You are a coding agent. Review code, write tests, fix bugs, and implement features.
|
|
11944
|
+
}`,rows:"4"}});t&&(ae.value=l.transportJson),ae.addEventListener("input",()=>{l.transportJson=ae.value});let ge=a.createDiv({cls:"af-create-footer"});if(t){let S=ge.createEl("button",{cls:"af-btn-sm danger"});T(S,"trash-2","af-btn-icon"),S.appendText(" Delete"),S.onclick=()=>{new ut(s.app,{title:`Delete channel "${t.name}"?`,body:"The channel file will be moved to your system trash and can be recovered.",confirmText:"Delete",danger:!0,onConfirm:async()=>{await s.repository.deleteChannel(t.name),new Fe.Notice(`Channel "${t.name}" deleted.`),await new Promise(j=>window.setTimeout(j,200)),await s.refreshFromVault(),e.navigate("channels")}}).open()},ge.createDiv({cls:"af-toolbar-spacer"})}let et=ge.createEl("button",{cls:"af-btn-sm",text:"Cancel"});et.onclick=()=>e.navigate("channels");let xe=ge.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(xe,t?"check":"plus","af-btn-icon"),xe.appendText(t?" Save Changes":" Create Channel");let Ke=S=>S.split(/[\n,]+/).map(j=>j.trim()).filter(Boolean),_e=S=>S.split(",").map(j=>j.trim()).filter(Boolean),Le=()=>{if(l.transportJson.trim())try{let S=JSON.parse(l.transportJson);return S&&typeof S=="object"&&!Array.isArray(S)?S:(new Fe.Notice("Transport config must be a JSON object."),null)}catch(S){return new Fe.Notice(`Transport JSON is invalid: ${S instanceof Error?S.message:String(S)}`),null}};t?xe.onclick=async()=>{let S=Le();if(S===null)return;S===void 0&&(S={});let j=e.markSubmitBusy(xe,"Saving...","check","Save Changes");try{await s.repository.updateChannel(t.name,{type:l.type,default_agent:l.defaultAgent,allowed_agents:l.allowedAgents.length>0?l.allowedAgents:[],enabled:l.enabled,credential_ref:l.credentialRef,allowed_users:Ke(l.allowedUsers),per_user_sessions:l.perUserSessions,channel_context:l.channelContext.trim(),tags:_e(l.tags),body:l.body.trim(),transport:S}),new Fe.Notice(`Channel "${t.name}" updated.`),await s.refreshFromVault(),e.navigate("channels")}catch(ce){let Se=ce instanceof Error?ce.message:String(ce);new Fe.Notice(`Failed to update channel: ${Se}`),j()}}:xe.onclick=async()=>{let S=l.name.trim();if(!S){new Fe.Notice("Channel name is required.");return}if(!l.credentialRef){new Fe.Notice("Select a credential.");return}let j=Le();if(j===null)return;let ce={name:z(S),type:l.type,default_agent:l.defaultAgent,allowed_agents:l.allowedAgents.length>0?l.allowedAgents:void 0,enabled:l.enabled,credential_ref:l.credentialRef,allowed_users:Ke(l.allowedUsers),per_user_sessions:l.perUserSessions,channel_context:l.channelContext.trim()||void 0,tags:_e(l.tags).length>0?_e(l.tags):void 0,transport:j},Se=e.markSubmitBusy(xe,"Creating...","plus","Create Channel");try{let Oe=z(S),Wt=await s.repository.getAvailablePath(s.repository.getSubfolder("channels"),Oe);await s.app.vault.create(Wt,U(ce,l.body.trim())),new Fe.Notice(`Channel "${Oe}" created.`),await s.refreshFromVault(),e.navigate("edit-channel",Oe)}catch(Oe){let Wt=Oe instanceof Error?Oe.message:String(Oe);new Fe.Notice(`Failed to create channel: ${Wt}`),Se()}}}var de=require("obsidian");var Ps=require("obsidian"),Qh=["bot","brain","shield-check","search","file-text","rocket","wand","sparkles","zap","target","compass","eye","code","terminal","database","globe","mail","message-circle","book","pen-tool","palette","music","camera","chart-bar","clipboard","cpu","server","cloud","lock","key","bell","calendar","clock","heart","star","flag","bookmark"],Ca=class extends Ps.Modal{constructor(t,s,n){super(t);this.onSelect=n;this.selectedIcon=s}searchQuery="";selectedIcon;allIcons=[];gridContainer;onOpen(){this.allIcons=(0,Ps.getIconIds)().sort();let{contentEl:t}=this;t.empty(),t.addClass("af-icon-picker-modal");let s=t.createEl("input",{cls:"af-icon-picker-search",attr:{type:"text",placeholder:"Search icons...",value:this.searchQuery}});this.gridContainer=t.createDiv({cls:"af-icon-picker-scroll"}),this.renderGrid(),s.addEventListener("input",()=>{this.searchQuery=s.value,this.renderGrid()}),window.setTimeout(()=>s.focus(),0)}renderGrid(){let t=this.gridContainer;t.empty();let s=this.searchQuery.toLowerCase().trim();if(!s)this.renderSection(t,"Popular",Qh),this.renderSection(t,"All Icons",this.allIcons);else{let n=this.allIcons.filter(i=>i.includes(s)),r=n.length===0?"No results":`${n.length} result${n.length!==1?"s":""}`;this.renderSection(t,r,n)}}renderSection(t,s,n){let r=t.createDiv({cls:"af-icon-picker-section"});r.createDiv({cls:"af-icon-picker-section-label",text:s});let i=r.createDiv({cls:"af-icon-picker-grid"});for(let o of n)this.renderIconItem(i,o)}renderIconItem(t,s){let n=t.createDiv({cls:`af-icon-picker-item${this.selectedIcon===s?" selected":""}`});n.setAttribute("title",s),n.setAttribute("aria-label",s),(0,Ps.setIcon)(n,s),n.addEventListener("click",()=>{this.selectedIcon=s,this.onSelect(s),this.close()})}onClose(){this.contentEl.empty()}};function Ta(a){let e={freq:"daily",hour:9,minute:0,days:[1],dayOfMonth:1};if(!a?.trim())return e;let t={"*/5 * * * *":"every_5m","*/15 * * * *":"every_15m","*/30 * * * *":"every_30m","0 * * * *":"every_hour","0 */2 * * *":"every_2h"};if(t[a])return{...e,freq:t[a]};let s=a.trim().split(/\s+/);if(s.length!==5)return e;let[n,r,i,,o]=s,l=parseInt(r??"9",10),c=parseInt(n??"0",10);if(i==="*"&&o==="*")return{...e,freq:"daily",hour:l,minute:c};if(i==="*"&&o==="1-5")return{...e,freq:"weekdays",hour:l,minute:c};if(i==="*"&&o!=="*"){let d=(o??"1").split(",").map(u=>parseInt(u,10));return{...e,freq:"weekly",hour:l,minute:c,days:d}}return o==="*"&&i!=="*"?{...e,freq:"monthly",hour:l,minute:c,dayOfMonth:parseInt(i??"1",10)}:{...e,hour:l,minute:c}}var Jl=[["claude-code","Claude Code",!1],["codex","Codex",!1],["process","Process (coming soon)",!0],["http","HTTP (coming soon)",!0]],Xl=[["bypassPermissions","Bypass Permissions","Auto-approve everything except deny list"],["dontAsk","Don\u2019t Ask","Auto-approve all tool calls"],["acceptEdits","Accept Edits","Auto-approve file edits, block bash unless allowed"],["plan","Plan","Read-only mode, no writes or commands"],["default","Default","Ask for each tool call"]],Ql=[["bypassPermissions","Bypass (no sandbox)","No sandbox, auto-approve everything"],["workspace-write","Workspace Write","Sandboxed: writes only inside the working dir"],["read-only","Read Only","Sandboxed: no writes or side-effect commands"]];function Es(a){let e=a.trim().toLowerCase();return e==="codex"||e==="openai-codex"}function _a(a){return Es(a)?Ql:Xl}function Aa(a,e){if(Es(e))switch(a){case"acceptEdits":case"default":return"workspace-write";case"plan":return"read-only";case"dontAsk":return"bypassPermissions";default:return Ql.some(([t])=>t===a)?a:"bypassPermissions"}switch(a){case"workspace-write":return"acceptEdits";case"read-only":return"plan";case"danger-full-access":return"bypassPermissions";default:return Xl.some(([t])=>t===a)?a:"bypassPermissions"}}function Zl(a){return Es(a)?"Codex enforces permissions via sandbox modes \u2014 your Claude mode was mapped: Accept Edits/Default \u2248 Workspace Write, Plan \u2248 Read Only, Don\u2019t Ask \u2248 Bypass.":"Claude Code uses permission modes \u2014 your Codex sandbox was mapped: Workspace Write \u2248 Accept Edits, Read Only \u2248 Plan."}function ec(a,e){let t=Ta(e.heartbeatSchedule),s=a.createDiv({cls:"af-form-row"});s.createDiv({cls:"af-form-label",text:"Frequency"});let n=s.createEl("select",{cls:"af-form-select"}),r=[["every_5m","Every 5 minutes"],["every_15m","Every 15 minutes"],["every_30m","Every 30 minutes"],["every_hour","Every hour"],["every_2h","Every 2 hours"],["every_4h","Every 4 hours"],["every_6h","Every 6 hours"],["every_12h","Every 12 hours"],["daily","Once a day"]],i="every_hour",o={"*/5 * * * *":"every_5m","*/15 * * * *":"every_15m","*/30 * * * *":"every_30m","0 * * * *":"every_hour","0 */2 * * *":"every_2h","0 */4 * * *":"every_4h","0 */6 * * *":"every_6h","0 */12 * * *":"every_12h"};o[e.heartbeatSchedule]?i=o[e.heartbeatSchedule]:(t.freq==="daily"||t.freq==="weekdays")&&(i="daily");for(let[m,f]of r){let g=n.createEl("option",{text:f,attr:{value:m}});m===i&&(g.selected=!0)}let l=a.createDiv({cls:"af-form-row af-schedule-time-row"});l.createDiv({cls:"af-form-label",text:"Time"});let c=l.createDiv({cls:"af-schedule-time-selects"}),d=c.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let m=0;m<24;m++){let f=m>=12?"PM":"AM",g=m===0?12:m>12?m-12:m,w=d.createEl("option",{text:`${g} ${f}`,attr:{value:String(m)}});m===t.hour&&(w.selected=!0)}c.createSpan({cls:"af-schedule-colon",text:":"});let u=c.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let m=0;m<60;m+=5){let f=u.createEl("option",{text:String(m).padStart(2,"0"),attr:{value:String(m)}});m===t.minute&&(f.selected=!0)}let h=()=>{l.setCssStyles({display:n.value==="daily"?"":"none"})},p=()=>{let m=n.value,f=d.value,g=u.value;switch(m){case"every_5m":e.heartbeatSchedule="*/5 * * * *";break;case"every_15m":e.heartbeatSchedule="*/15 * * * *";break;case"every_30m":e.heartbeatSchedule="*/30 * * * *";break;case"every_hour":e.heartbeatSchedule="0 * * * *";break;case"every_2h":e.heartbeatSchedule="0 */2 * * *";break;case"every_4h":e.heartbeatSchedule="0 */4 * * *";break;case"every_6h":e.heartbeatSchedule="0 */6 * * *";break;case"every_12h":e.heartbeatSchedule="0 */12 * * *";break;case"daily":e.heartbeatSchedule=`${g} ${f} * * *`;break}};n.addEventListener("change",()=>{h(),p()}),d.addEventListener("change",p),u.addEventListener("change",p),h()}function tc(a,e,t){a.createDiv({cls:"af-form-hint",text:"Servers from the MCP Servers tab. Checked servers are available to this agent on any adapter (Claude or Codex). Leave all unchecked to grant every enabled server."});let s=e.plugin.repository.getMcpServers();if(s.length===0){let r=a.createDiv({cls:"af-form-hint"});r.appendText("No MCP servers registered yet. ");let i=r.createEl("a",{cls:"af-link",text:"Add one in the MCP Servers tab."});i.onclick=o=>{o.preventDefault(),e.navigate("mcp")};return}let n=a.createDiv({cls:"af-create-skills-grid"});for(let r of s){let i=n.createDiv({cls:"af-mcp-agent-item"}),o=i.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});o.checked=t.has(r.name),o.addEventListener("change",()=>{o.checked?t.add(r.name):t.delete(r.name)});let c=i.createDiv({cls:"af-mcp-agent-label"}).createDiv({cls:"af-mcp-agent-name-row"}),d=c.createSpan({cls:`af-mcp-status-dot ${r.enabled?"idle":"disabled"}`});d.title=r.enabled?"enabled":"disabled",c.createSpan({cls:"af-create-skill-name",text:r.name}),c.createSpan({cls:"af-mcp-agent-tool-count",text:r.type}),r.enabled||c.createSpan({cls:"af-mcp-agent-tool-count af-muted",text:"disabled"})}}function sc(a,e){let{plugin:t}=e,s=a.createDiv({cls:"af-detail-header"}),n=s.createDiv({cls:"af-detail-header-left"}),r=n.createDiv({cls:"af-agent-card-avatar idle"});(0,de.setIcon)(r,"plus");let i=n.createDiv();i.createDiv({cls:"af-detail-header-name",text:"Create New Agent"}),i.createDiv({cls:"af-detail-header-desc",text:"Configure a new agent for your fleet"}),s.createDiv({cls:"af-detail-header-actions"});let o={name:"",description:"",avatar:"",tags:"",systemPrompt:"",model:"default",adapter:"claude-code",cwd:"",timeout:300,permissionMode:"bypassPermissions",effort:"",selectedSkills:new Set,selectedMcpServers:new Set,skillsBody:"",contextBody:"",approvalRequired:"",memory:!0,enabled:!0,allowedCommands:"",blockedCommands:"",heartbeatEnabled:!1,heartbeatSchedule:"0 */6 * * *",heartbeatBody:"",heartbeatNotify:!0,heartbeatChannel:"",heartbeatChannelTarget:"",autoCompactThreshold:85,wikiReferences:[]},l={none:{label:"None",prompt:""},coding:{label:"Coding Agent",prompt:`You are a coding agent. Review code, write tests, fix bugs, and implement features.
|
|
11963
11945
|
Follow existing code conventions. Write clean, well-tested code.
|
|
11964
11946
|
If something is unclear, ask for clarification instead of guessing.`},monitor:{label:"Monitor",prompt:`You are a monitoring agent. Check system status, alert on failures, and report on health metrics.
|
|
11965
11947
|
Be concise and factual. Highlight anomalies clearly.
|
|
@@ -11967,13 +11949,23 @@ Include timestamps and relevant context in all reports.`},briefing:{label:"Brief
|
|
|
11967
11949
|
Prioritize recent and important changes. Keep summaries concise.
|
|
11968
11950
|
End with explicit next actions if they exist.`},reviewer:{label:"Code Reviewer",prompt:`You are a code review agent. Analyze pull requests, suggest improvements, and flag potential issues.
|
|
11969
11951
|
Focus on correctness, security, and maintainability.
|
|
11970
|
-
Be specific \u2014 reference file names and line numbers.`}},d=s.createDiv({cls:"af-create-form"}),u=d.createDiv({cls:"af-create-section"}),p=u.createDiv({cls:"af-create-section-header"}),m=p.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(m,"user"),p.createSpan({text:"Identity"}),this.createFormField(u,"Name","deploy-watcher","Unique identifier (will be slugified)",B=>{l.name=B}),this.createFormField(u,"Description","Monitors deployments and reports status","",B=>{l.description=B});let f=u.createDiv({cls:"af-form-row"});f.createDiv({cls:"af-form-label",text:"Avatar"});let g=f.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"text",placeholder:"\u{1F6E1}\uFE0F"}});g.addEventListener("input",()=>{l.avatar=g.value}),this.createFormField(u,"Tags","devops, monitoring","Comma-separated",B=>{l.tags=B});let y=u.createDiv({cls:"af-form-row af-form-row-toggle"});y.createDiv({cls:"af-form-label",text:"Enabled"});let v=y.createDiv({cls:"af-agent-card-toggle on"});v.onclick=()=>{let B=v.hasClass("on");v.toggleClass("on",!B),l.enabled=!B};let k=d.createDiv({cls:"af-create-section"}),w=k.createDiv({cls:"af-create-section-header"}),S=w.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(S,"message-square"),w.createSpan({text:"System Prompt"});let T=k.createDiv({cls:"af-form-row"});T.createDiv({cls:"af-form-label",text:"Template"});let _=T.createEl("select",{cls:"af-form-select"});for(let[B,{label:V}]of Object.entries(h))_.createEl("option",{text:V,attr:{value:B}});let D=k.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"You are a deployment monitoring agent...",rows:"10"}});D.addEventListener("input",()=>{l.systemPrompt=D.value}),_.addEventListener("change",()=>{let B=h[_.value];B&&_.value!=="none"&&(l.systemPrompt=B.prompt,D.value=B.prompt)});let O=d.createDiv({cls:"af-create-section"}),C=O.createDiv({cls:"af-create-section-header"}),E=C.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(E,"settings"),C.createSpan({text:"Runtime Config"});let P=O.createDiv({cls:"af-create-config-grid"}),N=P.createDiv({cls:"af-form-row"});N.createDiv({cls:"af-form-label",text:"Adapter"});let M=N.createEl("select",{cls:"af-form-select"});for(let[B,V,Ee]of Xo){let we=M.createEl("option",{text:V,attr:{value:B,...Ee?{disabled:"true"}:{}}});B==="claude-code"&&(we.selected=!0)}let U=P.createDiv({cls:"af-form-row"}),$=U.createDiv({cls:"af-form-label",text:"Model"});this.addTooltip($,`Aliases (opus/sonnet/haiku/opusplan) work on any backend. Choose Custom\u2026 for a pinned ID or Bedrock/Vertex/Foundry. Blank = use Settings default (${this.plugin.settings.defaultModel||"CLI default"}).`);let Z=U.createDiv({cls:"af-form-field-wrap"}),de=()=>{Rt(Z,{value:l.model,adapter:l.adapter,onChange:B=>{l.model=B}})};de();let me=()=>{};M.addEventListener("change",()=>{l.adapter=M.value,(Ls(l.adapter)?Qs:Zs).some(V=>V.value===l.model.trim())&&(l.model=""),de(),l.permissionMode=Hn(l.permissionMode,l.adapter),me()});let ge=P.createDiv({cls:"af-form-row"});ge.createDiv({cls:"af-form-label",text:"Working Dir"});let X=ge.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Leave empty for vault root"}});X.addEventListener("input",()=>{l.cwd=X.value});let W=P.createDiv({cls:"af-form-row"});W.createDiv({cls:"af-form-label",text:"Timeout (sec)"});let K=W.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",value:"300"}});K.addEventListener("input",()=>{let B=parseInt(K.value,10);!isNaN(B)&&B>0&&(l.timeout=B)});let ne=P.createDiv({cls:"af-form-row"});ne.createDiv({cls:"af-form-label",text:"Permission Mode"});let G=ne.createEl("select",{cls:"af-form-select"}),ee=P.createDiv({cls:"af-form-hint",text:""});me=()=>{l.permissionMode=Hn(l.permissionMode,l.adapter);let B=Wn(l.adapter);G.empty();for(let[V,Ee]of B){let we=G.createEl("option",{text:Ee,attr:{value:V}});V===l.permissionMode&&(we.selected=!0)}ee.textContent=B.find(([V])=>V===G.value)?.[2]??""},me(),G.addEventListener("change",()=>{l.permissionMode=G.value,ee.textContent=Wn(l.adapter).find(([B])=>B===G.value)?.[2]??""});let Q=P.createDiv({cls:"af-form-row"});Q.createDiv({cls:"af-form-label",text:"Effort Level"});let ae=Q.createEl("select",{cls:"af-form-select"});for(let[B,V]of[["","Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]])ae.createEl("option",{text:V,attr:{value:B}});ae.addEventListener("change",()=>{l.effort=ae.value}),P.createDiv({cls:"af-form-hint",text:"Controls reasoning depth \u2014 low is fast, max is most thorough"});let ve=P.createDiv({cls:"af-form-row"}),Pe=ve.createDiv({cls:"af-form-label",text:"Auto-compact at"});this.addTooltip(Pe,"Percent of context window at which the chat auto-invokes /compact before the next message. 85% is a good default. Set 0 to disable.");let Ie=ve.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",min:"0",max:"100",value:String(l.autoCompactThreshold)}});Ie.addEventListener("input",()=>{let B=parseInt(Ie.value,10);!isNaN(B)&&B>=0&&B<=100&&(l.autoCompactThreshold=B)}),P.createDiv({cls:"af-form-hint",text:"0 disables auto-compact"});{let B=this.plugin.runtime.getSnapshot().agents.filter(V=>V.wikiKeeper!==void 0);if(B.length>0){let V=P.createDiv({cls:"af-form-row af-form-row-toggle"}),Ee=V.createDiv({cls:"af-form-label",text:"Wiki access"});this.addTooltip(Ee,"Lets this agent read + cite from the selected Wiki Keeper scopes (requires the wiki-query skill).");let we=V.createDiv({cls:"af-form-field-wrap"});for(let Ae of B){let nt=we.createEl("label",{cls:"af-form-checkbox-row"}),je=nt.createEl("input",{attr:{type:"checkbox"}});nt.createSpan({text:` ${Ae.name}`,cls:"af-form-checkbox-label"}),je.addEventListener("change",()=>{je.checked?l.wikiReferences.includes(Ae.name)||l.wikiReferences.push(Ae.name):l.wikiReferences=l.wikiReferences.filter(Tt=>Tt!==Ae.name)})}}}{let B=d.createDiv({cls:"af-create-section"}),V=B.createDiv({cls:"af-create-section-header"}),Ee=V.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ee,"heart-pulse");let we=V.createSpan({text:"Heartbeat"});this.addTooltip(we,"Autonomous periodic run \u2014 what the agent does when no one is asking");let Ae=B.createDiv({cls:"af-form-row af-form-row-toggle"});Ae.createDiv({cls:"af-form-label",text:"Enabled"});let nt=Ae.createDiv({cls:"af-agent-card-toggle"}),je=B.createDiv();je.setCssStyles({display:"none"}),nt.onclick=()=>{let ze=nt.hasClass("on");nt.toggleClass("on",!ze),l.heartbeatEnabled=!ze,je.setCssStyles({display:ze?"none":""})},this.renderHeartbeatSchedule(je,l);let Tt=je.createDiv({cls:"af-form-row af-form-row-toggle"}),Ut=Tt.createDiv({cls:"af-form-label"});Ut.setText("Notify"),this.addTooltip(Ut,"Show an Obsidian notice when the heartbeat completes");let bt=Tt.createDiv({cls:"af-agent-card-toggle on"});bt.onclick=()=>{let ze=bt.hasClass("on");bt.toggleClass("on",!ze),l.heartbeatNotify=!ze};let hs=this.plugin.runtime.getSnapshot(),Ns=je.createDiv({cls:"af-form-row"}),$t=Ns.createDiv({cls:"af-form-label"});$t.setText("Post to channel"),this.addTooltip($t,"Heartbeat results are posted to this Slack channel when the run completes");let L=Ns.createEl("select",{cls:"af-form-select"});L.createEl("option",{text:"(none)",attr:{value:""}});for(let ze of hs.channels)L.createEl("option",{text:ze.name,attr:{value:ze.name}});L.addEventListener("change",()=>{l.heartbeatChannel=L.value,qe()});let Y=je.createDiv({cls:"af-form-row"}),Te=Y.createDiv({cls:"af-form-label"});Te.setText("Target ID"),this.addTooltip(Te,"Specific channel id to post to (Discord/Slack channel id, Telegram chat id). Empty = DM the channel\u2019s first allowed user.");let Le=Y.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Channel/chat id \u2014 empty = DM"}});Le.value=l.heartbeatChannelTarget,Le.addEventListener("input",()=>{l.heartbeatChannelTarget=Le.value.trim()});let qe=()=>{Y.setCssStyles({display:l.heartbeatChannel?"":"none"})};qe();let at=je.createDiv({cls:"af-form-label"});at.setCssStyles({width:"auto"}),at.setCssStyles({marginTop:"12px"}),at.setText("Instruction"),this.addTooltip(at,'What the agent does on each heartbeat. Also used by the "Run Now" button.');let We=je.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Check status, scan for issues, report findings...",rows:"8"}});We.addEventListener("input",()=>{l.heartbeatBody=We.value})}let Me=d.createDiv({cls:"af-create-section"}),Fe=Me.createDiv({cls:"af-create-section-header"}),ke=Fe.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(ke,"puzzle"),Fe.createSpan({text:"Skills"});let Oe=this.plugin.runtime.getSnapshot();if(Oe.skills.length>0){Me.createDiv({cls:"af-form-sublabel",text:"Shared Skills"});let B=Me.createDiv({cls:"af-create-skills-grid"});for(let V of Oe.skills){let Ee=B.createDiv({cls:"af-create-skill-item"}),we=Ee.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});we.addEventListener("change",()=>{we.checked?l.selectedSkills.add(V.name):l.selectedSkills.delete(V.name)});let Ae=Ee.createDiv({cls:"af-create-skill-label"});Ae.createSpan({cls:"af-create-skill-name",text:V.name}),V.description&&Ae.createSpan({cls:"af-create-skill-desc",text:` \u2014 ${V.description}`})}}let Ue=Me.createDiv({cls:"af-form-sublabel"});Ue.setText("Agent-specific skills"),this.addTooltip(Ue,"Custom skills/instructions only for this agent, not shared with others");let Ne=Me.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Custom skills/instructions for this agent...",rows:"4"}});Ne.addEventListener("input",()=>{l.skillsBody=Ne.value});{let B=d.createDiv({cls:"af-create-section"}),V=B.createDiv({cls:"af-create-section-header"}),Ee=V.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ee,"plug");let we=V.createSpan({text:"MCP Servers"});this.addTooltip(we,"Grant agent access to MCP servers"),this.renderAgentMcpPicker(B,l.selectedMcpServers)}let q=d.createDiv({cls:"af-create-section"}),re=q.createDiv({cls:"af-create-section-header"}),j=re.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(j,"file-text");let Ce=re.createSpan({text:"Context"});this.addTooltip(Ce,"Project-specific context included in every run");let xe=q.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Background info, repo structure, conventions...",rows:"4"}});xe.addEventListener("input",()=>{l.contextBody=xe.value});let he=d.createDiv({cls:"af-create-section"}),$e=he.createDiv({cls:"af-create-section-header"}),ie=$e.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(ie,"shield-check"),$e.createSpan({text:"Permissions"}),this.createFormField(he,"Approval required","git_push, file_delete","Comma-separated tool names",B=>{l.approvalRequired=B});let I=he.createDiv({cls:"af-form-row"});I.createDiv({cls:"af-form-label",text:"Allowed Commands"});let se=I.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(curl *)
|
|
11952
|
+
Be specific \u2014 reference file names and line numbers.`}},c=a.createDiv({cls:"af-create-form"}),d=c.createDiv({cls:"af-create-section"}),u=d.createDiv({cls:"af-create-section-header"}),h=u.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(h,"user"),u.createSpan({text:"Identity"}),e.createFormField(d,"Name","deploy-watcher","Unique identifier (will be slugified)",L=>{o.name=L}),e.createFormField(d,"Description","Monitors deployments and reports status","",L=>{o.description=L});let p=d.createDiv({cls:"af-form-row"});p.createDiv({cls:"af-form-label",text:"Avatar"});let m=p.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"text",placeholder:"\u{1F6E1}\uFE0F"}});m.addEventListener("input",()=>{o.avatar=m.value}),e.createFormField(d,"Tags","devops, monitoring","Comma-separated",L=>{o.tags=L});let f=d.createDiv({cls:"af-form-row af-form-row-toggle"});f.createDiv({cls:"af-form-label",text:"Enabled"});let g=f.createDiv({cls:"af-agent-card-toggle on"});g.onclick=()=>{let L=g.hasClass("on");g.toggleClass("on",!L),o.enabled=!L};let w=c.createDiv({cls:"af-create-section"}),y=w.createDiv({cls:"af-create-section-header"}),v=y.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(v,"message-square"),y.createSpan({text:"System Prompt"});let k=w.createDiv({cls:"af-form-row"});k.createDiv({cls:"af-form-label",text:"Template"});let b=k.createEl("select",{cls:"af-form-select"});for(let[L,{label:V}]of Object.entries(l))b.createEl("option",{text:V,attr:{value:L}});let P=w.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"You are a deployment monitoring agent...",rows:"10"}});P.addEventListener("input",()=>{o.systemPrompt=P.value}),b.addEventListener("change",()=>{let L=l[b.value];L&&b.value!=="none"&&(o.systemPrompt=L.prompt,P.value=L.prompt)});let A=c.createDiv({cls:"af-create-section"}),M=A.createDiv({cls:"af-create-section-header"}),E=M.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(E,"settings"),M.createSpan({text:"Runtime Config"});let x=A.createDiv({cls:"af-create-config-grid"}),_=x.createDiv({cls:"af-form-row"});_.createDiv({cls:"af-form-label",text:"Adapter"});let R=_.createEl("select",{cls:"af-form-select"});for(let[L,V,De]of Jl){let Re=R.createEl("option",{text:V,attr:{value:L,...De?{disabled:"true"}:{}}});L==="claude-code"&&(Re.selected=!0)}let O=x.createDiv({cls:"af-form-row"}),F=O.createDiv({cls:"af-form-label",text:"Model"});e.addTooltip(F,`Aliases (opus/sonnet/haiku/opusplan) work on any backend. Choose Custom\u2026 for a pinned ID or Bedrock/Vertex/Foundry. Blank = use Settings default (${t.settings.defaultModel||"CLI default"}).`);let B=O.createDiv({cls:"af-form-field-wrap"}),q=()=>{Nt(B,{value:o.model,adapter:o.adapter,onChange:L=>{o.model=L}})};q();let oe=()=>{},be=()=>{};R.addEventListener("change",()=>{o.adapter=R.value,(Es(o.adapter)?Nn:Bn).some(V=>V.value===o.model.trim())&&(o.model=""),q(),o.permissionMode=Aa(o.permissionMode,o.adapter),oe(),be()});let ne=x.createDiv({cls:"af-form-row"});ne.createDiv({cls:"af-form-label",text:"Working Dir"});let Y=ne.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Leave empty for vault root"}});Y.addEventListener("input",()=>{o.cwd=Y.value});let H=x.createDiv({cls:"af-form-row"});H.createDiv({cls:"af-form-label",text:"Timeout (sec)"});let X=H.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",value:"300"}});X.addEventListener("input",()=>{let L=parseInt(X.value,10);!isNaN(L)&&L>0&&(o.timeout=L)});let me=x.createDiv({cls:"af-form-row"});me.createDiv({cls:"af-form-label",text:"Permission Mode"});let ee=me.createEl("select",{cls:"af-form-select"}),J=x.createDiv({cls:"af-form-hint",text:""});oe=()=>{o.permissionMode=Aa(o.permissionMode,o.adapter);let L=_a(o.adapter);ee.empty();for(let[V,De]of L){let Re=ee.createEl("option",{text:De,attr:{value:V}});V===o.permissionMode&&(Re.selected=!0)}J.textContent=L.find(([V])=>V===ee.value)?.[2]??""},oe();let K=x.createDiv({cls:"af-form-hint af-adapter-map-hint"});K.setCssStyles({display:"none"}),be=()=>{K.setText(Zl(o.adapter)),K.setCssStyles({display:""})},ee.addEventListener("change",()=>{o.permissionMode=ee.value,J.textContent=_a(o.adapter).find(([L])=>L===ee.value)?.[2]??""});let ke=x.createDiv({cls:"af-form-row"});ke.createDiv({cls:"af-form-label",text:"Effort Level"});let je=ke.createEl("select",{cls:"af-form-select"});for(let[L,V]of[["","Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]])je.createEl("option",{text:V,attr:{value:L}});je.addEventListener("change",()=>{o.effort=je.value}),x.createDiv({cls:"af-form-hint",text:"Controls reasoning depth \u2014 low is fast, max is most thorough"});let Qe=x.createDiv({cls:"af-form-row"}),Ze=Qe.createDiv({cls:"af-form-label",text:"Auto-compact at"});e.addTooltip(Ze,"Percent of context window at which the chat auto-invokes /compact before the next message. 85% is a good default. Set 0 to disable.");let He=Qe.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",min:"0",max:"100",value:String(o.autoCompactThreshold)}});He.addEventListener("input",()=>{let L=parseInt(He.value,10);!isNaN(L)&&L>=0&&L<=100&&(o.autoCompactThreshold=L)}),x.createDiv({cls:"af-form-hint",text:"0 disables auto-compact"});{let L=t.runtime.getSnapshot().agents.filter(V=>V.wikiKeeper!==void 0);if(L.length>0){let V=x.createDiv({cls:"af-form-row af-form-row-toggle"}),De=V.createDiv({cls:"af-form-label",text:"Wiki access"});e.addTooltip(De,"Lets this agent read + cite from the selected Wiki Keeper scopes (requires the wiki-query skill).");let Re=V.createDiv({cls:"af-form-field-wrap"});for(let ye of L){let Ue=Re.createEl("label",{cls:"af-form-checkbox-row"}),$e=Ue.createEl("input",{attr:{type:"checkbox"}});Ue.createSpan({text:` ${ye.name}`,cls:"af-form-checkbox-label"}),$e.addEventListener("change",()=>{$e.checked?o.wikiReferences.includes(ye.name)||o.wikiReferences.push(ye.name):o.wikiReferences=o.wikiReferences.filter(Ot=>Ot!==ye.name)})}}}{let L=c.createDiv({cls:"af-create-section"}),V=L.createDiv({cls:"af-create-section-header"}),De=V.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(De,"heart-pulse");let Re=V.createSpan({text:"Heartbeat"});e.addTooltip(Re,"Autonomous periodic run \u2014 what the agent does when no one is asking");let ye=L.createDiv({cls:"af-form-row af-form-row-toggle"});ye.createDiv({cls:"af-form-label",text:"Enabled"});let Ue=ye.createDiv({cls:"af-agent-card-toggle"}),$e=L.createDiv();$e.setCssStyles({display:"none"}),Ue.onclick=()=>{let ct=Ue.hasClass("on");Ue.toggleClass("on",!ct),o.heartbeatEnabled=!ct,$e.setCssStyles({display:ct?"none":""})},ec($e,o);let Ot=$e.createDiv({cls:"af-form-row af-form-row-toggle"}),qt=Ot.createDiv({cls:"af-form-label"});qt.setText("Notify"),e.addTooltip(qt,"Show an Obsidian notice when the heartbeat completes");let zt=Ot.createDiv({cls:"af-agent-card-toggle on"});zt.onclick=()=>{let ct=zt.hasClass("on");zt.toggleClass("on",!ct),o.heartbeatNotify=!ct};let Ia=t.runtime.getSnapshot(),Gt=$e.createDiv({cls:"af-form-row"}),I=Gt.createDiv({cls:"af-form-label"});I.setText("Post to channel"),e.addTooltip(I,"Heartbeat results are posted to this Slack channel when the run completes");let te=Gt.createEl("select",{cls:"af-form-select"});te.createEl("option",{text:"(none)",attr:{value:""}});for(let ct of Ia.channels)te.createEl("option",{text:ct.name,attr:{value:ct.name}});te.addEventListener("change",()=>{o.heartbeatChannel=te.value,Ct()});let ue=$e.createDiv({cls:"af-form-row"}),Ae=ue.createDiv({cls:"af-form-label"});Ae.setText("Target ID"),e.addTooltip(Ae,"Specific channel id to post to (Discord/Slack channel id, Telegram chat id). Empty = DM the channel\u2019s first allowed user.");let Ne=ue.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Channel/chat id \u2014 empty = DM"}});Ne.value=o.heartbeatChannelTarget,Ne.addEventListener("input",()=>{o.heartbeatChannelTarget=Ne.value.trim()});let Ct=()=>{ue.setCssStyles({display:o.heartbeatChannel?"":"none"})};Ct();let Be=$e.createDiv({cls:"af-form-label"});Be.setCssStyles({width:"auto"}),Be.setCssStyles({marginTop:"12px"}),Be.setText("Instruction"),e.addTooltip(Be,'What the agent does on each heartbeat. Also used by the "Run Now" button.');let Vt=$e.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Check status, scan for issues, report findings...",rows:"8"}});Vt.addEventListener("input",()=>{o.heartbeatBody=Vt.value})}let $=c.createDiv({cls:"af-create-section"}),ae=$.createDiv({cls:"af-create-section-header"}),ge=ae.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(ge,"puzzle"),ae.createSpan({text:"Skills"});let et=t.runtime.getSnapshot();if(et.skills.length>0){$.createDiv({cls:"af-form-sublabel",text:"Shared Skills"});let L=$.createDiv({cls:"af-create-skills-grid"});for(let V of et.skills){let De=L.createDiv({cls:"af-create-skill-item"}),Re=De.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});Re.addEventListener("change",()=>{Re.checked?o.selectedSkills.add(V.name):o.selectedSkills.delete(V.name)});let ye=De.createDiv({cls:"af-create-skill-label"});ye.createSpan({cls:"af-create-skill-name",text:V.name}),V.description&&ye.createSpan({cls:"af-create-skill-desc",text:` \u2014 ${V.description}`})}}let xe=$.createDiv({cls:"af-form-sublabel"});xe.setText("Agent-specific skills"),e.addTooltip(xe,"Custom skills/instructions only for this agent, not shared with others");let Ke=$.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Custom skills/instructions for this agent...",rows:"4"}});Ke.addEventListener("input",()=>{o.skillsBody=Ke.value});{let L=c.createDiv({cls:"af-create-section"}),V=L.createDiv({cls:"af-create-section-header"}),De=V.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(De,"plug");let Re=V.createSpan({text:"MCP Servers"});e.addTooltip(Re,"Grant agent access to MCP servers"),tc(L,e,o.selectedMcpServers)}let _e=c.createDiv({cls:"af-create-section"}),Le=_e.createDiv({cls:"af-create-section-header"}),S=Le.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(S,"file-text");let j=Le.createSpan({text:"Context"});e.addTooltip(j,"Project-specific context included in every run");let ce=_e.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Background info, repo structure, conventions...",rows:"4"}});ce.addEventListener("input",()=>{o.contextBody=ce.value});let Se=c.createDiv({cls:"af-create-section"}),Oe=Se.createDiv({cls:"af-create-section-header"}),Wt=Oe.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(Wt,"shield-check"),Oe.createSpan({text:"Permissions"}),e.createFormField(Se,"Approval required","git_push, file_delete","Comma-separated tool names",L=>{o.approvalRequired=L});let mn=Se.createDiv({cls:"af-form-row"});mn.createDiv({cls:"af-form-label",text:"Allowed Commands"});let ls=mn.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(curl *)
|
|
11953
|
+
Bash(python3 *)
|
|
11954
|
+
Read
|
|
11955
|
+
Edit
|
|
11956
|
+
Write`,rows:"4"}});ls.addEventListener("input",()=>{o.allowedCommands=ls.value});let lt=Se.createDiv({cls:"af-form-row"});lt.createDiv({cls:"af-form-label",text:"Blocked Commands"});let Fs=lt.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(git push *)
|
|
11957
|
+
Bash(rm -rf *)
|
|
11958
|
+
Bash(sudo *)`,rows:"4"}});Fs.addEventListener("input",()=>{o.blockedCommands=Fs.value}),Se.createDiv({cls:"af-form-hint",text:"On Codex agents these become execpolicy command rules \u2014 only Bash(cmd args *) prefixes are enforced; tool-name rules (Read/Write) and mid-pattern wildcards are ignored, and file/network access is governed by Permission Mode (the sandbox)."});let fn=Se.createDiv({cls:"af-form-row"});fn.createDiv({cls:"af-form-label",text:"Memory enabled"});let cs=fn.createDiv({cls:"af-agent-card-toggle on"});cs.onclick=()=>{let L=cs.hasClass("on");cs.toggleClass("on",!L),o.memory=!L};let ds=a.createDiv({cls:"af-create-footer"}),gn=ds.createEl("button",{cls:"af-btn-sm",text:"Cancel"});gn.onclick=()=>e.navigate("agents");let Lt=ds.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(Lt,"plus","af-btn-icon"),Lt.appendText(" Create Agent"),Lt.onclick=async()=>{let L=o.name.trim();if(!L){new de.Notice("Agent name is required.");return}let V=z(L);if(t.repository.getAgentByName(V)){new de.Notice(`Agent "${V}" already exists.`);return}let De=ye=>ye.split(",").map(Ue=>Ue.trim()).filter(Boolean),Re=e.markSubmitBusy(Lt,"Creating...","plus","Create Agent");try{let ye=Ue=>re(Ue).map($e=>$e.trim()).filter(Boolean);await t.repository.createAgentFolder({name:V,description:o.description.trim(),avatar:o.avatar.trim(),tags:De(o.tags),systemPrompt:o.systemPrompt.trim(),model:o.model.trim()||"default",adapter:o.adapter,cwd:o.cwd.trim(),timeout:o.timeout,permissionMode:o.permissionMode,effort:o.effort||void 0,approvalRequired:De(o.approvalRequired),memory:o.memory,memoryMaxEntries:100,skills:Array.from(o.selectedSkills),mcpServers:Array.from(o.selectedMcpServers),skillsBody:o.skillsBody.trim(),contextBody:o.contextBody.trim(),enabled:o.enabled,permissionRules:{allow:ye(o.allowedCommands),deny:ye(o.blockedCommands)},autoCompactThreshold:o.autoCompactThreshold,wikiReferences:o.wikiReferences}),o.heartbeatEnabled&&o.heartbeatBody.trim()&&await t.repository.updateHeartbeat(V,{enabled:o.heartbeatEnabled,schedule:o.heartbeatSchedule.trim(),notify:o.heartbeatNotify,channel:o.heartbeatChannel,channelTarget:o.heartbeatChannel?o.heartbeatChannelTarget:"",body:o.heartbeatBody.trim()}),new de.Notice(`Agent "${V}" created.`),await t.refreshFromVault(),e.navigate("agent-detail",V)}catch(ye){let Ue=ye instanceof Error?ye.message:String(ye);new de.Notice(`Failed to create agent: ${Ue}`),Re()}}}function nc(a,e,t){let{plugin:s}=e,n=a.createDiv({cls:"af-detail-header"}),r=n.createDiv({cls:"af-detail-header-left"}),i=r.createDiv({cls:"af-agent-card-avatar idle"});(0,de.setIcon)(i,"edit");let o=r.createDiv();o.createDiv({cls:"af-detail-header-name",text:`Edit Agent: ${t.name}`}),o.createDiv({cls:"af-detail-header-desc",text:"Modify agent configuration"}),n.createDiv({cls:"af-detail-header-actions"});let l={name:t.name,description:t.description??"",avatar:t.avatar,tags:t.tags.join(", "),systemPrompt:t.body,model:t.model,adapter:t.adapter,cwd:t.cwd??"",timeout:t.timeout,permissionMode:t.permissionMode,effort:t.effort??"",selectedSkills:new Set(t.skills),selectedMcpServers:new Set(t.mcpServers??[]),skillsBody:t.skillsBody,contextBody:t.contextBody,approvalRequired:t.approvalRequired.join(", "),memory:t.memory,memoryTokenBudget:t.memoryTokenBudget,reflectionEnabled:t.reflection.enabled,reflectionProposeSkills:t.reflection.proposeSkills,enabled:t.enabled,allowedCommands:t.permissionRules.allow.join(`
|
|
11959
|
+
`),blockedCommands:t.permissionRules.deny.join(`
|
|
11960
|
+
`),heartbeatEnabled:t.heartbeatEnabled,heartbeatSchedule:t.heartbeatSchedule,heartbeatBody:t.heartbeatBody,heartbeatNotify:t.heartbeatNotify,heartbeatChannel:t.heartbeatChannel,heartbeatChannelTarget:t.heartbeatChannelTarget,autoCompactThreshold:t.autoCompactThreshold??85,wikiReferences:(t.wikiReferences??[]).map(I=>I.agent)},c=a.createDiv({cls:"af-create-form"}),d=c.createDiv({cls:"af-create-section"}),u=d.createDiv({cls:"af-create-section-header"}),h=u.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(h,"user"),u.createSpan({text:"Identity"});let p=d.createDiv({cls:"af-form-row"});p.createDiv({cls:"af-form-label",text:"Name"}),p.createEl("input",{cls:"af-form-input",attr:{type:"text",value:t.name,disabled:"true"}}).setCssStyles({opacity:"0.6"}),e.createFormField(d,"Description","Monitors deployments and reports status","",I=>{l.description=I},t.description??"");let f=d.createDiv({cls:"af-form-row"});f.createDiv({cls:"af-form-label",text:"Avatar"});let g=f.createEl("button",{cls:"af-avatar-picker-btn"}),w=g.createDiv({cls:"af-avatar-picker-preview"});e.renderAgentAvatar(w,{...t,avatar:l.avatar??t.avatar}),g.createSpan({cls:"af-avatar-picker-label",text:l.avatar||t.avatar||"Pick icon\u2026"}),g.addEventListener("click",()=>{new Ca(s.app,l.avatar??t.avatar,I=>{l.avatar=I,w.empty(),(0,de.setIcon)(w,I),g.querySelector(".af-avatar-picker-label")?.setText(I)}).open()}),e.createFormField(d,"Tags","devops, monitoring","Comma-separated",I=>{l.tags=I},t.tags.join(", "));let y=d.createDiv({cls:"af-form-row"});y.createDiv({cls:"af-form-label",text:"Enabled"});let v=y.createDiv({cls:`af-agent-card-toggle${t.enabled?" on":""}`});v.onclick=()=>{let I=v.hasClass("on");v.toggleClass("on",!I),l.enabled=!I};let k=c.createDiv({cls:"af-create-section"}),b=k.createDiv({cls:"af-create-section-header"}),P=b.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(P,"message-square"),b.createSpan({text:"System Prompt"});let A=k.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"System prompt...",rows:"10"}});A.value=t.body,A.addEventListener("input",()=>{l.systemPrompt=A.value});let M=c.createDiv({cls:"af-create-section"}),E=M.createDiv({cls:"af-create-section-header"}),x=E.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(x,"settings"),E.createSpan({text:"Runtime Config"});let _=M.createDiv({cls:"af-create-config-grid"}),R=_.createDiv({cls:"af-form-row"});R.createDiv({cls:"af-form-label",text:"Adapter"});let O=R.createEl("select",{cls:"af-form-select"});for(let[I,te,ue]of Jl){let Ae=O.createEl("option",{text:te,attr:{value:I,...ue?{disabled:"true"}:{}}});(I===t.adapter||Es(t.adapter)&&I==="codex")&&(Ae.selected=!0)}let F=_.createDiv({cls:"af-form-row"}),B=F.createDiv({cls:"af-form-label",text:"Model"});e.addTooltip(B,`Aliases (opus/sonnet/haiku/opusplan) work on any backend. Choose Custom\u2026 for a pinned ID or Bedrock/Vertex/Foundry. Blank = use Settings default (${s.settings.defaultModel||"CLI default"}).`);let q=F.createDiv({cls:"af-form-field-wrap"}),oe=()=>{Nt(q,{value:l.model,adapter:l.adapter,onChange:I=>{l.model=I}})};oe();let be=()=>{},ne=()=>{};O.addEventListener("change",()=>{l.adapter=O.value,(Es(l.adapter)?Nn:Bn).some(te=>te.value===l.model.trim())&&(l.model=""),oe(),l.permissionMode=Aa(l.permissionMode,l.adapter),be(),ne()});let Y=_.createDiv({cls:"af-form-row"});Y.createDiv({cls:"af-form-label",text:"Working Dir"});let H=Y.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Leave empty for vault root",value:t.cwd??""}});H.addEventListener("input",()=>{l.cwd=H.value});let X=_.createDiv({cls:"af-form-row"});X.createDiv({cls:"af-form-label",text:"Timeout (sec)"});let me=X.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",value:String(t.timeout)}});me.addEventListener("input",()=>{let I=parseInt(me.value,10);!isNaN(I)&&I>0&&(l.timeout=I)});let ee=_.createDiv({cls:"af-form-row"});ee.createDiv({cls:"af-form-label",text:"Permission Mode"});let J=ee.createEl("select",{cls:"af-form-select"}),K=_.createDiv({cls:"af-form-hint",text:""});be=()=>{l.permissionMode=Aa(l.permissionMode,l.adapter);let I=_a(l.adapter);J.empty();for(let[te,ue]of I){let Ae=J.createEl("option",{text:ue,attr:{value:te}});te===l.permissionMode&&(Ae.selected=!0)}K.textContent=I.find(([te])=>te===J.value)?.[2]??""},be();let ke=_.createDiv({cls:"af-form-hint af-adapter-map-hint"});ke.setCssStyles({display:"none"}),ne=()=>{ke.setText(Zl(l.adapter)),ke.setCssStyles({display:""})},J.addEventListener("change",()=>{l.permissionMode=J.value,K.textContent=_a(l.adapter).find(([I])=>I===J.value)?.[2]??""});let je=_.createDiv({cls:"af-form-row"});je.createDiv({cls:"af-form-label",text:"Effort Level"});let Qe=je.createEl("select",{cls:"af-form-select"});for(let[I,te]of[["","Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]]){let ue=Qe.createEl("option",{text:te,attr:{value:I}});I===(t.effort??"")&&(ue.selected=!0)}Qe.addEventListener("change",()=>{l.effort=Qe.value}),_.createDiv({cls:"af-form-hint",text:"Controls reasoning depth \u2014 low is fast, max is most thorough"});let Ze=_.createDiv({cls:"af-form-row"}),He=Ze.createDiv({cls:"af-form-label",text:"Auto-compact at"});e.addTooltip(He,"Percent of context window at which the chat auto-invokes /compact before the next message. 85% is a good default. Set 0 to disable.");let $=Ze.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",min:"0",max:"100",value:String(l.autoCompactThreshold)}});$.addEventListener("input",()=>{let I=parseInt($.value,10);!isNaN(I)&&I>=0&&I<=100&&(l.autoCompactThreshold=I)}),_.createDiv({cls:"af-form-hint",text:"0 disables auto-compact"});{let I=s.runtime.getSnapshot().agents.filter(te=>te.wikiKeeper!==void 0);if(I.length>0){let te=_.createDiv({cls:"af-form-row af-form-row-toggle"}),ue=te.createDiv({cls:"af-form-label",text:"Wiki access"});e.addTooltip(ue,"Lets this agent read + cite from the selected Wiki Keeper scopes (requires the wiki-query skill).");let Ae=te.createDiv({cls:"af-form-field-wrap"});for(let Ne of I){let Ct=Ae.createEl("label",{cls:"af-form-checkbox-row"}),Be=Ct.createEl("input",{attr:{type:"checkbox"}});l.wikiReferences.includes(Ne.name)&&(Be.checked=!0),Ct.createSpan({text:` ${Ne.name}`,cls:"af-form-checkbox-label"}),Be.addEventListener("change",()=>{Be.checked?l.wikiReferences.includes(Ne.name)||l.wikiReferences.push(Ne.name):l.wikiReferences=l.wikiReferences.filter(Vt=>Vt!==Ne.name)})}}}if(t.isFolder){let I=c.createDiv({cls:"af-create-section"}),te=I.createDiv({cls:"af-create-section-header"}),ue=te.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(ue,"heart-pulse");let Ae=te.createSpan({text:"Heartbeat"});e.addTooltip(Ae,"Autonomous periodic run \u2014 what the agent does when no one is asking");let Ne=I.createDiv({cls:"af-form-row af-form-row-toggle"});Ne.createDiv({cls:"af-form-label",text:"Enabled"});let Ct=Ne.createDiv({cls:`af-agent-card-toggle${l.heartbeatEnabled?" on":""}`}),Be=I.createDiv();Be.setCssStyles({display:l.heartbeatEnabled?"":"none"}),Ct.onclick=()=>{let vt=Ct.hasClass("on");Ct.toggleClass("on",!vt),l.heartbeatEnabled=!vt,Be.setCssStyles({display:vt?"none":""})},ec(Be,l);let Vt=Be.createDiv({cls:"af-form-row af-form-row-toggle"}),ct=Vt.createDiv({cls:"af-form-label"});ct.setText("Notify"),e.addTooltip(ct,"Show an Obsidian notice when the heartbeat completes");let Ma=Vt.createDiv({cls:`af-agent-card-toggle${l.heartbeatNotify?" on":""}`});Ma.onclick=()=>{let vt=Ma.hasClass("on");Ma.toggleClass("on",!vt),l.heartbeatNotify=!vt};let Fc=s.runtime.getSnapshot(),Gr=Be.createDiv({cls:"af-form-row"}),Vr=Gr.createDiv({cls:"af-form-label"});Vr.setText("Post to channel"),e.addTooltip(Vr,"Heartbeat results are posted to this Slack channel when the run completes");let yn=Gr.createEl("select",{cls:"af-form-select"});yn.createEl("option",{text:"(none)",attr:{value:""}});for(let vt of Fc.channels){let Lc=yn.createEl("option",{text:vt.name,attr:{value:vt.name}});vt.name===l.heartbeatChannel&&(Lc.selected=!0)}yn.addEventListener("change",()=>{l.heartbeatChannel=yn.value,Kr()});let Fa=Be.createDiv({cls:"af-form-row"}),Yr=Fa.createDiv({cls:"af-form-label"});Yr.setText("Target ID"),e.addTooltip(Yr,"Specific channel id to post to (Discord/Slack channel id, Telegram chat id). Empty = DM the channel\u2019s first allowed user.");let La=Fa.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Channel/chat id \u2014 empty = DM"}});La.value=l.heartbeatChannelTarget,La.addEventListener("input",()=>{l.heartbeatChannelTarget=La.value.trim()});let Kr=()=>{Fa.setCssStyles({display:l.heartbeatChannel?"":"none"})};Kr();let vn=Be.createDiv({cls:"af-form-label"});vn.setCssStyles({width:"auto"}),vn.setCssStyles({marginTop:"12px"}),vn.setText("Instruction"),e.addTooltip(vn,'What the agent does on each heartbeat. Also used by the "Run Now" button.');let Oa=Be.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Check status, scan for issues, report findings...",rows:"8"}});Oa.value=l.heartbeatBody,Oa.addEventListener("input",()=>{l.heartbeatBody=Oa.value})}let ae=c.createDiv({cls:"af-create-section"}),ge=ae.createDiv({cls:"af-create-section-header"}),et=ge.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(et,"puzzle"),ge.createSpan({text:"Skills"});let xe=s.runtime.getSnapshot();if(xe.skills.length>0){ae.createDiv({cls:"af-form-sublabel",text:"Shared Skills"});let I=ae.createDiv({cls:"af-create-skills-grid"});for(let te of xe.skills){let ue=I.createDiv({cls:"af-create-skill-item"}),Ae=ue.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});Ae.checked=l.selectedSkills.has(te.name),Ae.addEventListener("change",()=>{Ae.checked?l.selectedSkills.add(te.name):l.selectedSkills.delete(te.name)});let Ne=ue.createDiv({cls:"af-create-skill-label"});Ne.createSpan({cls:"af-create-skill-name",text:te.name}),te.description&&Ne.createSpan({cls:"af-create-skill-desc",text:` \u2014 ${te.description}`})}}let Ke=ae.createDiv({cls:"af-form-sublabel"});Ke.setText("Agent-specific skills"),e.addTooltip(Ke,"Custom skills/instructions only for this agent, not shared with others");let _e=ae.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Custom skills/instructions for this agent...",rows:"4"}});_e.value=t.skillsBody,_e.addEventListener("input",()=>{l.skillsBody=_e.value});let Le=c.createDiv({cls:"af-create-section"}),S=Le.createDiv({cls:"af-create-section-header"}),j=S.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(j,"plug");let ce=S.createSpan({text:"MCP Servers"});e.addTooltip(ce,"Grant agent access to MCP servers"),tc(Le,e,l.selectedMcpServers);let Se=c.createDiv({cls:"af-create-section"}),Oe=Se.createDiv({cls:"af-create-section-header"}),Wt=Oe.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(Wt,"file-text");let mn=Oe.createSpan({text:"Context"});e.addTooltip(mn,"Project-specific context included in every run");let ls=Se.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Background info, repo structure, conventions...",rows:"4"}});ls.value=t.contextBody,ls.addEventListener("input",()=>{l.contextBody=ls.value});let lt=c.createDiv({cls:"af-create-section"}),Fs=lt.createDiv({cls:"af-create-section-header"}),fn=Fs.createSpan({cls:"af-create-section-icon"});(0,de.setIcon)(fn,"shield-check"),Fs.createSpan({text:"Permissions"}),e.createFormField(lt,"Approval required","git_push, file_delete","Comma-separated tool names",I=>{l.approvalRequired=I},t.approvalRequired.join(", "));let cs=lt.createDiv({cls:"af-form-row"});cs.createDiv({cls:"af-form-label",text:"Allowed Commands"});let ds=cs.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(curl *)
|
|
11971
11961
|
Bash(python3 *)
|
|
11972
11962
|
Read
|
|
11973
11963
|
Edit
|
|
11974
|
-
Write`,rows:"4"}});
|
|
11964
|
+
Write`,rows:"4"}});ds.value=t.permissionRules.allow.join(`
|
|
11965
|
+
`),ds.addEventListener("input",()=>{l.allowedCommands=ds.value});let gn=lt.createDiv({cls:"af-form-row"});gn.createDiv({cls:"af-form-label",text:"Blocked Commands"});let Lt=gn.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(git push *)
|
|
11975
11966
|
Bash(rm -rf *)
|
|
11976
|
-
Bash(sudo *)`,rows:"4"}});
|
|
11967
|
+
Bash(sudo *)`,rows:"4"}});Lt.value=t.permissionRules.deny.join(`
|
|
11968
|
+
`),Lt.addEventListener("input",()=>{l.blockedCommands=Lt.value}),lt.createDiv({cls:"af-form-hint",text:"On Codex agents these become execpolicy command rules \u2014 only Bash(cmd args *) prefixes are enforced; tool-name rules (Read/Write) and mid-pattern wildcards are ignored, and file/network access is governed by Permission Mode (the sandbox)."});let L=lt.createDiv({cls:"af-form-row"});L.createDiv({cls:"af-form-label",text:"Memory enabled"});let V=L.createDiv({cls:`af-agent-card-toggle${t.memory?" on":""}`});V.onclick=()=>{let I=V.hasClass("on");V.toggleClass("on",!I),l.memory=!I};let De=lt.createDiv({cls:"af-form-row"});De.createDiv({cls:"af-form-label",text:"Memory token budget"});let Re=De.createEl("input",{cls:"af-create-input",attr:{type:"number",min:"200",step:"100"}});Re.value=String(l.memoryTokenBudget),Re.addEventListener("input",()=>{let I=parseInt(Re.value,10);Number.isFinite(I)&&(l.memoryTokenBudget=I)});let ye=lt.createDiv({cls:"af-form-row"});ye.createDiv({cls:"af-form-label",text:"Nightly reflection"});let Ue=ye.createDiv({cls:`af-agent-card-toggle${t.reflection.enabled?" on":""}`});Ue.onclick=()=>{let I=Ue.hasClass("on");Ue.toggleClass("on",!I),l.reflectionEnabled=!I};let $e=lt.createDiv({cls:"af-form-row"});$e.createDiv({cls:"af-form-label",text:"Propose skills from memory"});let Ot=$e.createDiv({cls:`af-agent-card-toggle${t.reflection.proposeSkills?" on":""}`});Ot.onclick=()=>{let I=Ot.hasClass("on");Ot.toggleClass("on",!I),l.reflectionProposeSkills=!I};let qt=a.createDiv({cls:"af-create-footer"}),zt=qt.createEl("button",{cls:"af-btn-sm danger"});T(zt,"trash-2","af-btn-icon"),zt.appendText(" Delete"),zt.onclick=()=>void s.deleteAgent(t.name),qt.createDiv({cls:"af-toolbar-spacer"});let Ia=qt.createEl("button",{cls:"af-btn-sm",text:"Cancel"});Ia.onclick=()=>e.navigate("agent-detail",t.name);let Gt=qt.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(Gt,"check","af-btn-icon"),Gt.appendText(" Save Changes"),Gt.onclick=async()=>{let I=ue=>ue.split(",").map(Ae=>Ae.trim()).filter(Boolean),te=e.markSubmitBusy(Gt,"Saving...","check","Save Changes");try{let ue=Ae=>re(Ae).map(Ne=>Ne.trim()).filter(Boolean);await s.repository.updateAgent(t.name,{description:l.description.trim(),avatar:l.avatar.trim(),tags:I(l.tags),systemPrompt:l.systemPrompt.trim(),model:l.model.trim()||"default",adapter:l.adapter,cwd:l.cwd.trim(),timeout:l.timeout,permissionMode:l.permissionMode,effort:l.effort||void 0,approvalRequired:I(l.approvalRequired),memory:l.memory,memoryTokenBudget:l.memoryTokenBudget,reflectionEnabled:l.reflectionEnabled,reflectionProposeSkills:l.reflectionProposeSkills,skills:Array.from(l.selectedSkills),mcpServers:Array.from(l.selectedMcpServers),skillsBody:l.skillsBody.trim(),contextBody:l.contextBody.trim(),enabled:l.enabled,permissionRules:{allow:ue(l.allowedCommands),deny:ue(l.blockedCommands)},autoCompactThreshold:l.autoCompactThreshold,wikiReferences:l.wikiReferences}),t.isFolder&&await s.repository.updateHeartbeat(t.name,{enabled:l.heartbeatEnabled,schedule:l.heartbeatSchedule.trim(),notify:l.heartbeatNotify,channel:l.heartbeatChannel,channelTarget:l.heartbeatChannel?l.heartbeatChannelTarget:"",body:l.heartbeatBody.trim()}),new de.Notice(`Agent "${t.name}" updated.`),await s.refreshFromVault(),e.navigate("agent-detail",t.name)}catch(ue){let Ae=ue instanceof Error?ue.message:String(ue);new de.Notice(`Failed to update agent: ${Ae}`),te()}}}var Ee=require("obsidian");function ac(a,e){let t=Ta(e.schedule),s=a.createDiv({cls:"af-form-row"});s.createDiv({cls:"af-form-label",text:"Frequency"});let n=s.createEl("select",{cls:"af-form-select"}),r=[["every_5m","Every 5 minutes"],["every_15m","Every 15 minutes"],["every_30m","Every 30 minutes"],["every_hour","Every hour"],["every_2h","Every 2 hours"],["daily","Daily"],["weekdays","Weekdays"],["weekly","Weekly"],["monthly","Monthly"]];for(let[y,v]of r){let k=n.createEl("option",{text:v,attr:{value:y}});y===t.freq&&(k.selected=!0)}let i=a.createDiv({cls:"af-form-row af-schedule-time-row"});i.createDiv({cls:"af-form-label",text:"Time"});let o=i.createDiv({cls:"af-schedule-time-selects"}),l=o.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let y=0;y<24;y++){let v=y>=12?"PM":"AM",k=y===0?12:y>12?y-12:y,b=l.createEl("option",{text:`${k} ${v}`,attr:{value:String(y)}});y===t.hour&&(b.selected=!0)}o.createSpan({cls:"af-schedule-colon",text:":"});let c=o.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let y=0;y<60;y+=5){let v=c.createEl("option",{text:String(y).padStart(2,"0"),attr:{value:String(y)}});y===t.minute&&(v.selected=!0)}let d=a.createDiv({cls:"af-form-row af-schedule-day-row"});d.createDiv({cls:"af-form-label",text:"Day"});let u=d.createDiv({cls:"af-schedule-day-buttons"}),h=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],p=new Set(t.days);for(let y=0;y<7;y++){let v=u.createEl("button",{cls:`af-schedule-day-btn${p.has(y)?" active":""}`,text:h[y]});v.onclick=()=>{p.has(y)?p.delete(y):p.add(y),v.toggleClass("active",p.has(y)),w()}}let m=a.createDiv({cls:"af-form-row af-schedule-dom-row"});m.createDiv({cls:"af-form-label",text:"Day of month"});let f=m.createEl("select",{cls:"af-form-select af-form-select-sm"});for(let y=1;y<=28;y++){let v=f.createEl("option",{text:String(y),attr:{value:String(y)}});y===t.dayOfMonth&&(v.selected=!0)}let g=()=>{let y=n.value,v=["daily","weekdays","weekly","monthly"].includes(y),k=y==="weekly",b=y==="monthly";i.setCssStyles({display:v?"":"none"}),d.setCssStyles({display:k?"":"none"}),m.setCssStyles({display:b?"":"none"})},w=()=>{let y=n.value,v=l.value,k=c.value,b="";switch(y){case"every_5m":b="*/5 * * * *";break;case"every_15m":b="*/15 * * * *";break;case"every_30m":b="*/30 * * * *";break;case"every_hour":b="0 * * * *";break;case"every_2h":b="0 */2 * * *";break;case"daily":b=`${k} ${v} * * *`;break;case"weekdays":b=`${k} ${v} * * 1-5`;break;case"weekly":{let P=Array.from(p).sort().join(",")||"1";b=`${k} ${v} * * ${P}`;break}case"monthly":b=`${k} ${v} ${f.value} * *`;break}e.schedule=b,e.type="recurring"};n.addEventListener("change",()=>{g(),w()}),l.addEventListener("change",w),c.addEventListener("change",w),f.addEventListener("change",w),g()}function rc(a,e,t,s){let n=a.createDiv({cls:"af-form-row"}),r=n.createDiv({cls:"af-form-label",text:"Channel"}),i=n.createEl("select",{cls:"af-form-select"});i.createEl("option",{text:"\u2014 none (run log only) \u2014",attr:{value:""}});for(let u of t){let h=i.createEl("option",{text:u.name,attr:{value:u.name}});u.name===s.channel&&(h.selected=!0)}e.addTooltip(r,"Post this task\u2019s full output to a channel when it finishes. Leave as none to only write the run log (the default batched behavior).");let o=a.createDiv({cls:"af-form-row"}),l=o.createDiv({cls:"af-form-label",text:"Target ID"}),c=o.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Discord/Slack channel ID or Telegram chat ID \u2014 empty = DM you"}});c.value=s.channelTarget,c.addEventListener("input",()=>{s.channelTarget=c.value.trim()}),e.addTooltip(l,"Where in the channel to post. For Discord, enable Developer Mode and right-click the channel \u2192 Copy Channel ID. Leave empty to DM the first allowed user instead.");let d=()=>{o.setCssStyles({display:s.channel?"":"none"})};d(),i.addEventListener("change",()=>{s.channel=i.value,d()})}function Zh(a){let e=t=>String(t).padStart(2,"0");return`${a.getFullYear()}-${e(a.getMonth()+1)}-${e(a.getDate())}T${e(a.getHours())}:${e(a.getMinutes())}:${e(a.getSeconds())}`}function jr(a){let e=t=>String(t).padStart(2,"0");return`${a.getFullYear()}-${e(a.getMonth()+1)}-${e(a.getDate())}T${e(a.getHours())}:${e(a.getMinutes())}`}function ic(a,e,t){let s=a.createDiv({cls:"af-form-row"});s.createDiv({cls:"af-form-label",text:"Run"});let n=s.createDiv({cls:"af-segmented"}),r=[["immediate","Immediate"],["recurring","Recurring"],["once","One-time"]],i=[];for(let[o,l]of r){let c=n.createEl("button",{cls:`af-segmented-btn${o===e?" active":""}`,text:l});i.push([o,c]),c.onclick=()=>{for(let[d,u]of i)u.toggleClass("active",d===o);t(o)}}}function oc(a,e){let{plugin:t}=e,s=t.runtime.getSnapshot(),n=a.createDiv({cls:"af-detail-header"}),r=n.createDiv({cls:"af-detail-header-left"}),i=r.createDiv({cls:"af-agent-card-avatar idle"});(0,Ee.setIcon)(i,"plus");let o=r.createDiv();o.createDiv({cls:"af-detail-header-name",text:"Create New Task"}),o.createDiv({cls:"af-detail-header-desc",text:"Configure a new task for your fleet"}),n.createDiv({cls:"af-detail-header-actions"});let l={title:"",agent:s.agents[0]?.name??"",priority:"medium",tags:"",body:"",scheduleEnabled:!1,scheduleMode:"recurring",schedule:"0 9 * * *",runAt:"",type:"immediate",enabled:!0,catchUp:!0,effort:"",model:"",channel:"",channelTarget:""},c=a.createDiv({cls:"af-create-form"}),d=c.createDiv({cls:"af-create-section"}),u=d.createDiv({cls:"af-create-section-header"}),h=u.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(h,"file-text"),u.createSpan({text:"Task Details"}),e.createFormField(d,"Title","Daily status report","Used as the task identifier",$=>{l.title=$});let p=d.createDiv({cls:"af-form-row"});p.createDiv({cls:"af-form-label",text:"Agent"});let m=p.createEl("select",{cls:"af-form-select"});for(let $ of s.agents)m.createEl("option",{text:$.name,attr:{value:$.name}});m.addEventListener("change",()=>{l.agent=m.value});let f=d.createDiv({cls:"af-form-row"});f.createDiv({cls:"af-form-label",text:"Priority"});let g=f.createEl("select",{cls:"af-form-select"}),w=[["low","Low"],["medium","Medium"],["high","High"],["critical","Critical"]];for(let[$,ae]of w){let ge=g.createEl("option",{text:ae,attr:{value:$}});$==="medium"&&(ge.selected=!0)}g.addEventListener("change",()=>{l.priority=g.value}),e.createFormField(d,"Tags","monitoring, devops","Comma-separated",$=>{l.tags=$});let y=c.createDiv({cls:"af-create-section"}),v=y.createDiv({cls:"af-create-section-header"}),k=v.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(k,"message-square"),v.createSpan({text:"Instructions"});let b=y.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Describe what the agent should do...",rows:"10"}});b.addEventListener("input",()=>{l.body=b.value});let P=c.createDiv({cls:"af-create-section"}),A=P.createDiv({cls:"af-create-section-header"}),M=A.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(M,"clock"),A.createSpan({text:"Schedule"}),ic(P,"immediate",$=>{l.scheduleEnabled=$!=="immediate",$!=="immediate"&&(l.scheduleMode=$),l.type=$,E.setCssStyles({display:$==="immediate"?"none":""}),x.setCssStyles({display:$==="recurring"?"":"none"}),_.setCssStyles({display:$==="once"?"":"none"})});let E=P.createDiv({cls:"af-schedule-body"});E.setCssStyles({display:"none"});let x=E.createDiv(),_=E.createDiv();_.setCssStyles({display:"none"}),ac(x,l);let R=_.createDiv({cls:"af-form-row"});R.createDiv({cls:"af-form-label",text:"Run at"});let O=R.createEl("input",{cls:"af-form-input",attr:{type:"datetime-local",value:jr(new Date(Date.now()+36e5))}});l.runAt=new Date(O.value).toISOString(),O.addEventListener("input",()=>{l.runAt=O.value?new Date(O.value).toISOString():""});let F=E.createDiv({cls:"af-form-row af-form-row-toggle"});F.createDiv({cls:"af-form-label",text:"Enabled"});let B=F.createDiv({cls:"af-agent-card-toggle on"});B.onclick=()=>{let $=B.hasClass("on");B.toggleClass("on",!$),l.enabled=!$};let q=E.createDiv({cls:"af-form-row af-form-row-toggle"});q.createDiv({cls:"af-form-label"}).setText("Catch up if missed");let be=q.createDiv({cls:`af-agent-card-toggle${l.catchUp?" on":""}`});be.onclick=()=>{let $=be.hasClass("on");be.toggleClass("on",!$),l.catchUp=!$};let ne=c.createDiv({cls:"af-create-section"}),Y=ne.createDiv({cls:"af-create-section-header"}),H=Y.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(H,"gauge"),Y.createSpan({text:"Execution"});let X=ne.createDiv({cls:"af-form-row"}),me=X.createDiv({cls:"af-form-label",text:"Model"}),ee=X.createDiv({cls:"af-form-field-wrap"}),J=$=>{ee.empty();let ae=s.agents.find(ge=>ge.name===$);Nt(ee,{value:l.model,adapter:ae?.adapter,onChange:ge=>{l.model=ge},allowInherit:!0,inheritPlaceholder:ae?`Inherit from ${ae.name}${ae.model?` (${ae.model})`:""}`:"Inherit from agent"})};J(l.agent),m.addEventListener("change",()=>J(m.value)),e.addTooltip(me,"Override the agent\u2019s model for this task only. Useful for routing simple runs to haiku while the agent stays on opus for heavier work.");let K=ne.createDiv({cls:"af-form-row"}),ke=K.createDiv({cls:"af-form-label",text:"Effort"}),je=K.createEl("select",{cls:"af-form-select"});for(let[$,ae]of[["","Agent Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]]){let ge=je.createEl("option",{text:ae,attr:{value:$}});$===l.effort&&(ge.selected=!0)}je.addEventListener("change",()=>{l.effort=je.value}),rc(ne,e,s.channels,l),e.addTooltip(ke,"Overrides the agent\u2019s effort level for this task. Higher effort = more thinking tokens spent.");let Qe=a.createDiv({cls:"af-create-footer"}),Ze=Qe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});Ze.onclick=()=>e.navigate("kanban");let He=Qe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(He,"plus","af-btn-icon"),He.appendText(" Create Task"),He.onclick=async()=>{let $=l.title.trim();if(!$){new Ee.Notice("Task title is required.");return}let ae=z($),ge=_e=>_e.split(",").map(Le=>Le.trim()).filter(Boolean),et=l.scheduleEnabled?l.scheduleMode==="once"?"once":"recurring":"immediate",xe={task_id:ae,agent:l.agent,type:et,priority:l.priority,enabled:l.enabled,created:Zh(new Date),run_count:0,catch_up:l.catchUp,effort:l.effort||void 0,model:l.model||void 0,channel:l.channel||void 0,channel_target:l.channel&&l.channelTarget?l.channelTarget:void 0,tags:ge(l.tags)};if(et==="recurring")xe.schedule=l.schedule.trim()||"0 9 * * *";else if(et==="once"){if(!l.runAt){new Ee.Notice("Pick a date/time for the one-time run.");return}xe.run_at=l.runAt}let Ke=e.markSubmitBusy(He,"Creating...","plus","Create Task");try{let _e=await t.repository.getAvailablePath(t.repository.getSubfolder("tasks"),ae);await t.app.vault.create(_e,U(xe,l.body.trim()||"Describe the task here.")),new Ee.Notice(`Task "${ae}" created.`),await t.refreshFromVault(),e.navigate("task-detail",ae)}catch(_e){let Le=_e instanceof Error?_e.message:String(_e);new Ee.Notice(`Failed to create task: ${Le}`),Ke()}}}function lc(a,e,t){let{plugin:s}=e,n=s.runtime.getSnapshot(),r=a.createDiv({cls:"af-detail-header"}),i=r.createDiv({cls:"af-detail-header-left"}),o=i.createDiv({cls:"af-agent-card-avatar idle"});(0,Ee.setIcon)(o,"edit");let l=i.createDiv();l.createDiv({cls:"af-detail-header-name",text:`Edit Task: ${t.taskId}`}),l.createDiv({cls:"af-detail-header-desc",text:"Modify task configuration"}),r.createDiv({cls:"af-detail-header-actions"});let c=!!(t.schedule||t.runAt),d={agent:t.agent,type:t.type,priority:t.priority,schedule:t.schedule??"0 9 * * *",runAt:t.runAt??"",scheduleEnabled:c,scheduleMode:t.type==="once"?"once":"recurring",enabled:t.enabled,catchUp:t.catchUp,effort:t.effort??"",model:t.model??"",channel:t.channel??"",channelTarget:t.channelTarget??"",tags:t.tags.join(", "),body:t.body},u=a.createDiv({cls:"af-create-form"}),h=u.createDiv({cls:"af-create-section"}),p=h.createDiv({cls:"af-create-section-header"}),m=p.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(m,"file-text"),p.createSpan({text:"Task Details"});let f=h.createDiv({cls:"af-form-row"});f.createDiv({cls:"af-form-label",text:"Title"}),f.createEl("input",{cls:"af-form-input",attr:{type:"text",value:t.taskId,disabled:"true"}}).setCssStyles({opacity:"0.6"});let w=h.createDiv({cls:"af-form-row"});w.createDiv({cls:"af-form-label",text:"Agent"});let y=w.createEl("select",{cls:"af-form-select"});for(let S of n.agents){let j=y.createEl("option",{text:S.name,attr:{value:S.name}});S.name===t.agent&&(j.selected=!0)}y.addEventListener("change",()=>{d.agent=y.value});let v=h.createDiv({cls:"af-form-row"});v.createDiv({cls:"af-form-label",text:"Priority"});let k=v.createEl("select",{cls:"af-form-select"}),b=[["low","Low"],["medium","Medium"],["high","High"],["critical","Critical"]];for(let[S,j]of b){let ce=k.createEl("option",{text:j,attr:{value:S}});S===t.priority&&(ce.selected=!0)}k.addEventListener("change",()=>{d.priority=k.value}),e.createFormField(h,"Tags","monitoring, critical","Comma-separated",S=>{d.tags=S},t.tags.join(", "));let P=u.createDiv({cls:"af-create-section"}),A=P.createDiv({cls:"af-create-section-header"}),M=A.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(M,"message-square"),A.createSpan({text:"Instructions"});let E=P.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Describe what the agent should do...",rows:"10"}});E.value=t.body,E.addEventListener("input",()=>{d.body=E.value});let x=u.createDiv({cls:"af-create-section"}),_=x.createDiv({cls:"af-create-section-header"}),R=_.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(R,"clock"),_.createSpan({text:"Schedule"});let O=c?d.scheduleMode==="once"?"once":"recurring":"immediate";ic(x,O,S=>{d.scheduleEnabled=S!=="immediate",S!=="immediate"&&(d.scheduleMode=S),d.type=S,F.setCssStyles({display:S==="immediate"?"none":""}),B.setCssStyles({display:S==="recurring"?"":"none"}),q.setCssStyles({display:S==="once"?"":"none"})});let F=x.createDiv({cls:"af-schedule-body"});F.setCssStyles({display:c?"":"none"});let B=F.createDiv(),q=F.createDiv();B.setCssStyles({display:O==="recurring"?"":"none"}),q.setCssStyles({display:O==="once"?"":"none"}),ac(B,d);let oe=q.createDiv({cls:"af-form-row"});oe.createDiv({cls:"af-form-label",text:"Run at"});let be=d.runAt?jr(new Date(d.runAt)):jr(new Date(Date.now()+36e5)),ne=oe.createEl("input",{cls:"af-form-input",attr:{type:"datetime-local",value:be}});d.runAt||(d.runAt=new Date(ne.value).toISOString()),ne.addEventListener("input",()=>{d.runAt=ne.value?new Date(ne.value).toISOString():""});let Y=F.createDiv({cls:"af-form-row af-form-row-toggle"});Y.createDiv({cls:"af-form-label",text:"Enabled"});let H=Y.createDiv({cls:`af-agent-card-toggle${t.enabled?" on":""}`});H.onclick=()=>{let S=H.hasClass("on");H.toggleClass("on",!S),d.enabled=!S};let X=F.createDiv({cls:"af-form-row af-form-row-toggle"});X.createDiv({cls:"af-form-label"}).setText("Catch up if missed");let ee=X.createDiv({cls:`af-agent-card-toggle${d.catchUp?" on":""}`});ee.onclick=()=>{let S=ee.hasClass("on");ee.toggleClass("on",!S),d.catchUp=!S};let J=u.createDiv({cls:"af-create-section"}),K=J.createDiv({cls:"af-create-section-header"}),ke=K.createSpan({cls:"af-create-section-icon"});(0,Ee.setIcon)(ke,"gauge"),K.createSpan({text:"Execution"});let je=J.createDiv({cls:"af-form-row"}),Qe=je.createDiv({cls:"af-form-label",text:"Effort"}),Ze=je.createEl("select",{cls:"af-form-select"}),He=[["","Agent Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]];for(let[S,j]of He){let ce=Ze.createEl("option",{text:j,attr:{value:S}});S===d.effort&&(ce.selected=!0)}Ze.addEventListener("change",()=>{d.effort=Ze.value}),e.addTooltip(Qe,"Overrides the agent\u2019s effort level for this task. Higher effort = more thinking tokens spent.");let $=J.createDiv({cls:"af-form-row"}),ae=$.createDiv({cls:"af-form-label",text:"Model"}),ge=$.createDiv({cls:"af-form-field-wrap"}),et=S=>{ge.empty();let j=n.agents.find(ce=>ce.name===S);Nt(ge,{value:d.model,adapter:j?.adapter,onChange:ce=>{d.model=ce},allowInherit:!0,inheritPlaceholder:j?`Inherit from ${j.name}${j.model?` (${j.model})`:""}`:"Inherit from agent"})};et(d.agent),y.addEventListener("change",()=>et(y.value)),rc(J,e,n.channels,d),e.addTooltip(ae,"Override the agent\u2019s model for this task only. Useful for routing simple runs to haiku while the agent stays on opus for heavier work.");let xe=a.createDiv({cls:"af-create-footer"}),Ke=xe.createEl("button",{cls:"af-btn-sm danger"});T(Ke,"trash-2","af-btn-icon"),Ke.appendText(" Delete"),Ke.onclick=()=>{new ut(s.app,{title:`Delete task "${t.taskId}"?`,body:"The task file will be moved to your system trash and can be recovered.",confirmText:"Delete",danger:!0,onConfirm:async()=>{await s.repository.deleteTask(t.taskId),new Ee.Notice(`Task "${t.taskId}" deleted.`),await new Promise(S=>window.setTimeout(S,200)),await s.refreshFromVault(),e.navigate("kanban")}}).open()},xe.createDiv({cls:"af-toolbar-spacer"});let _e=xe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});_e.onclick=()=>e.navigate("task-detail",t.taskId);let Le=xe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(Le,"check","af-btn-icon"),Le.appendText(" Save Changes"),Le.onclick=async()=>{let S=Se=>Se.split(",").map(Oe=>Oe.trim()).filter(Boolean),j=d.scheduleEnabled?d.scheduleMode==="once"?"once":"recurring":"immediate";if(j==="once"&&!d.runAt){new Ee.Notice("Pick a date/time for the one-time run.");return}let ce=e.markSubmitBusy(Le,"Saving...","check","Save Changes");try{await s.repository.updateTask(t.taskId,{agent:d.agent,type:j,priority:d.priority,schedule:j==="recurring"?d.schedule.trim():"",runAt:j==="once"?d.runAt:"",enabled:d.enabled,catch_up:d.catchUp,effort:d.effort||void 0,model:d.model||"",channel:d.channel||"",channelTarget:d.channel&&d.channelTarget?d.channelTarget:"",tags:S(d.tags),body:d.body.trim()}),new Ee.Notice(`Task "${t.taskId}" updated.`),await s.refreshFromVault(),e.navigate("task-detail",t.taskId)}catch(Se){let Oe=Se instanceof Error?Se.message:String(Se);new Ee.Notice(`Failed to update task: ${Oe}`),ce()}}}var Ve=require("obsidian");function Hr(a,e,t){let{plugin:s}=e,n=a.createDiv({cls:"af-detail-header"}),r=n.createDiv({cls:"af-detail-header-left"}),i=r.createDiv({cls:"af-agent-card-avatar idle"});(0,Ve.setIcon)(i,t?"edit":"plus");let o=r.createDiv();t?(o.createDiv({cls:"af-detail-header-name",text:`Edit Skill: ${t.name}`}),o.createDiv({cls:"af-detail-header-desc",text:"Modify skill definition"})):(o.createDiv({cls:"af-detail-header-name",text:"Create New Skill"}),o.createDiv({cls:"af-detail-header-desc",text:"Define a reusable skill for your agents"})),n.createDiv({cls:"af-detail-header-actions"});let l={name:"",description:t?t.description??"":"",tags:t?t.tags.join(", "):"",body:t?t.body:"",toolsBody:t?t.toolsBody:"",referencesBody:t?t.referencesBody:"",examplesBody:t?t.examplesBody:""},c={none:{label:"None",prompt:""},cli:{label:"CLI Tool Wrapper",prompt:`You are using the {{tool}} CLI. All operations go through the wrapper script.
|
|
11977
11969
|
|
|
11978
11970
|
Requirements:
|
|
11979
11971
|
- Ensure required environment variables are set
|
|
@@ -12010,39 +12002,34 @@ Key behaviors:
|
|
|
12010
12002
|
- Use tables and charts where appropriate
|
|
12011
12003
|
- Always state the time range and filters applied
|
|
12012
12004
|
- Flag anomalies and outliers explicitly
|
|
12013
|
-
- End with actionable insights, not just observations`}},d=
|
|
12005
|
+
- End with actionable insights, not just observations`}},d=a.createDiv({cls:"af-create-form"}),u=d.createDiv({cls:"af-create-section"}),h=u.createDiv({cls:"af-create-section-header"}),p=h.createSpan({cls:"af-create-section-icon"});if((0,Ve.setIcon)(p,"puzzle"),h.createSpan({text:"Identity"}),t){let H=u.createDiv({cls:"af-form-row"});H.createDiv({cls:"af-form-label",text:"Name"}),H.createEl("input",{cls:"af-form-input",attr:{type:"text",value:t.name,disabled:"true"}}).setCssStyles({opacity:"0.6"})}else e.createFormField(u,"Name","todoist","Unique identifier (will be slugified)",H=>{l.name=H});e.createFormField(u,"Description","Manage tasks and projects via CLI","",H=>{l.description=H},t?t.description??"":void 0),e.createFormField(u,"Tags","productivity, tasks","Comma-separated",H=>{l.tags=H},t?t.tags.join(", "):void 0);let m=d.createDiv({cls:"af-create-section"}),f=m.createDiv({cls:"af-create-section-header"}),g=f.createSpan({cls:"af-create-section-icon"});(0,Ve.setIcon)(g,"file-text"),f.createSpan({text:"Core Instructions"});let w;if(!t){let H=m.createDiv({cls:"af-form-row"});H.createDiv({cls:"af-form-label",text:"Template"}),w=H.createEl("select",{cls:"af-form-select"});for(let[X,{label:me}]of Object.entries(c))w.createEl("option",{text:me,attr:{value:X}})}let y=m.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:t?"Skill instructions...":"Skill instructions \u2014 what does this skill do and how should agents use it?",rows:"10"}});if(t&&(y.value=t.body),y.addEventListener("input",()=>{l.body=y.value}),w){let H=w;H.addEventListener("change",()=>{let X=c[H.value];X&&H.value!=="none"&&(l.body=X.prompt,y.value=X.prompt)})}let v=d.createDiv({cls:"af-create-section"}),k=v.createDiv({cls:"af-create-section-header"}),b=k.createSpan({cls:"af-create-section-icon"});(0,Ve.setIcon)(b,"wrench");let P=k.createSpan({text:"Tools"});e.addTooltip(P,"CLI commands, API endpoints, and tool definitions available to agents using this skill");let A=v.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:t?`## Commands
|
|
12006
|
+
|
|
12007
|
+
### list
|
|
12008
|
+
...`:`## Commands
|
|
12014
12009
|
|
|
12015
12010
|
### list
|
|
12016
12011
|
Usage: tool list [--filter <query>]
|
|
12017
|
-
...`,rows:"8"}});
|
|
12012
|
+
...`,rows:"8"}});t&&(A.value=t.toolsBody),A.addEventListener("input",()=>{l.toolsBody=A.value});let M=d.createDiv({cls:"af-create-section"}),E=M.createDiv({cls:"af-create-section-header"}),x=E.createSpan({cls:"af-create-section-icon"});(0,Ve.setIcon)(x,"book-open");let _=E.createSpan({text:"References"});e.addTooltip(_,"Background docs, conventions, cheat sheets");let R=M.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"API docs, filter syntax, conventions...",rows:"6"}});t&&(R.value=t.referencesBody),R.addEventListener("input",()=>{l.referencesBody=R.value});let O=d.createDiv({cls:"af-create-section"}),F=O.createDiv({cls:"af-create-section-header"}),B=F.createSpan({cls:"af-create-section-icon"});(0,Ve.setIcon)(B,"message-circle");let q=F.createSpan({text:"Examples"});e.addTooltip(q,"Example prompts and ideal outputs showing how to use this skill");let oe=O.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:t?`## Example: List all tasks
|
|
12013
|
+
...`:`## Example: List all tasks
|
|
12018
12014
|
|
|
12019
12015
|
User: Show me my tasks for today
|
|
12020
12016
|
|
|
12021
|
-
Agent: ...`,rows:"6"}});
|
|
12022
|
-
`),blockedCommands:a.permissionRules.deny.join(`
|
|
12023
|
-
`),heartbeatEnabled:a.heartbeatEnabled,heartbeatSchedule:a.heartbeatSchedule,heartbeatBody:a.heartbeatBody,heartbeatNotify:a.heartbeatNotify,heartbeatChannel:a.heartbeatChannel,heartbeatChannelTarget:a.heartbeatChannelTarget,autoCompactThreshold:a.autoCompactThreshold??85,wikiReferences:(a.wikiReferences??[]).map(L=>L.agent)},u=s.createDiv({cls:"af-create-form"}),p=u.createDiv({cls:"af-create-section"}),m=p.createDiv({cls:"af-create-section-header"}),f=m.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(f,"user"),m.createSpan({text:"Identity"});let g=p.createDiv({cls:"af-form-row"});g.createDiv({cls:"af-form-label",text:"Name"}),g.createEl("input",{cls:"af-form-input",attr:{type:"text",value:a.name,disabled:"true"}}).setCssStyles({opacity:"0.6"}),this.createFormField(p,"Description","Monitors deployments and reports status","",L=>{d.description=L},a.description??"");let v=p.createDiv({cls:"af-form-row"});v.createDiv({cls:"af-form-label",text:"Avatar"});let k=v.createEl("button",{cls:"af-avatar-picker-btn"}),w=k.createDiv({cls:"af-avatar-picker-preview"});this.renderAgentAvatar(w,{...a,avatar:d.avatar??a.avatar}),k.createSpan({cls:"af-avatar-picker-label",text:d.avatar||a.avatar||"Pick icon\u2026"}),k.addEventListener("click",()=>{new $n(this.app,d.avatar??a.avatar,L=>{d.avatar=L,w.empty(),(0,b.setIcon)(w,L),k.querySelector(".af-avatar-picker-label")?.setText(L)}).open()}),this.createFormField(p,"Tags","devops, monitoring","Comma-separated",L=>{d.tags=L},a.tags.join(", "));let S=p.createDiv({cls:"af-form-row"});S.createDiv({cls:"af-form-label",text:"Enabled"});let T=S.createDiv({cls:`af-agent-card-toggle${a.enabled?" on":""}`});T.onclick=()=>{let L=T.hasClass("on");T.toggleClass("on",!L),d.enabled=!L};let _=u.createDiv({cls:"af-create-section"}),D=_.createDiv({cls:"af-create-section-header"}),O=D.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(O,"message-square"),D.createSpan({text:"System Prompt"});let C=_.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"System prompt...",rows:"10"}});C.value=a.body,C.addEventListener("input",()=>{d.systemPrompt=C.value});let E=u.createDiv({cls:"af-create-section"}),P=E.createDiv({cls:"af-create-section-header"}),N=P.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(N,"settings"),P.createSpan({text:"Runtime Config"});let M=E.createDiv({cls:"af-create-config-grid"}),U=M.createDiv({cls:"af-form-row"});U.createDiv({cls:"af-form-label",text:"Adapter"});let $=U.createEl("select",{cls:"af-form-select"});for(let[L,Y,Te]of Xo){let Le=$.createEl("option",{text:Y,attr:{value:L,...Te?{disabled:"true"}:{}}});(L===a.adapter||Ls(a.adapter)&&L==="codex")&&(Le.selected=!0)}let Z=M.createDiv({cls:"af-form-row"}),de=Z.createDiv({cls:"af-form-label",text:"Model"});this.addTooltip(de,`Aliases (opus/sonnet/haiku/opusplan) work on any backend. Choose Custom\u2026 for a pinned ID or Bedrock/Vertex/Foundry. Blank = use Settings default (${this.plugin.settings.defaultModel||"CLI default"}).`);let me=Z.createDiv({cls:"af-form-field-wrap"}),ge=()=>{Rt(me,{value:d.model,adapter:d.adapter,onChange:L=>{d.model=L}})};ge();let X=()=>{};$.addEventListener("change",()=>{d.adapter=$.value,(Ls(d.adapter)?Qs:Zs).some(Y=>Y.value===d.model.trim())&&(d.model=""),ge(),d.permissionMode=Hn(d.permissionMode,d.adapter),X()});let W=M.createDiv({cls:"af-form-row"});W.createDiv({cls:"af-form-label",text:"Working Dir"});let K=W.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Leave empty for vault root",value:a.cwd??""}});K.addEventListener("input",()=>{d.cwd=K.value});let ne=M.createDiv({cls:"af-form-row"});ne.createDiv({cls:"af-form-label",text:"Timeout (sec)"});let G=ne.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",value:String(a.timeout)}});G.addEventListener("input",()=>{let L=parseInt(G.value,10);!isNaN(L)&&L>0&&(d.timeout=L)});let ee=M.createDiv({cls:"af-form-row"});ee.createDiv({cls:"af-form-label",text:"Permission Mode"});let Q=ee.createEl("select",{cls:"af-form-select"}),ae=M.createDiv({cls:"af-form-hint",text:""});X=()=>{d.permissionMode=Hn(d.permissionMode,d.adapter);let L=Wn(d.adapter);Q.empty();for(let[Y,Te]of L){let Le=Q.createEl("option",{text:Te,attr:{value:Y}});Y===d.permissionMode&&(Le.selected=!0)}ae.textContent=L.find(([Y])=>Y===Q.value)?.[2]??""},X(),Q.addEventListener("change",()=>{d.permissionMode=Q.value,ae.textContent=Wn(d.adapter).find(([L])=>L===Q.value)?.[2]??""});let ve=M.createDiv({cls:"af-form-row"});ve.createDiv({cls:"af-form-label",text:"Effort Level"});let Pe=ve.createEl("select",{cls:"af-form-select"});for(let[L,Y]of[["","Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]]){let Te=Pe.createEl("option",{text:Y,attr:{value:L}});L===(a.effort??"")&&(Te.selected=!0)}Pe.addEventListener("change",()=>{d.effort=Pe.value}),M.createDiv({cls:"af-form-hint",text:"Controls reasoning depth \u2014 low is fast, max is most thorough"});let Ie=M.createDiv({cls:"af-form-row"}),Me=Ie.createDiv({cls:"af-form-label",text:"Auto-compact at"});this.addTooltip(Me,"Percent of context window at which the chat auto-invokes /compact before the next message. 85% is a good default. Set 0 to disable.");let Fe=Ie.createEl("input",{cls:"af-form-input af-form-input-sm",attr:{type:"number",min:"0",max:"100",value:String(d.autoCompactThreshold)}});Fe.addEventListener("input",()=>{let L=parseInt(Fe.value,10);!isNaN(L)&&L>=0&&L<=100&&(d.autoCompactThreshold=L)}),M.createDiv({cls:"af-form-hint",text:"0 disables auto-compact"});{let L=this.plugin.runtime.getSnapshot().agents.filter(Y=>Y.wikiKeeper!==void 0);if(L.length>0){let Y=M.createDiv({cls:"af-form-row af-form-row-toggle"}),Te=Y.createDiv({cls:"af-form-label",text:"Wiki access"});this.addTooltip(Te,"Lets this agent read + cite from the selected Wiki Keeper scopes (requires the wiki-query skill).");let Le=Y.createDiv({cls:"af-form-field-wrap"});for(let qe of L){let at=Le.createEl("label",{cls:"af-form-checkbox-row"}),We=at.createEl("input",{attr:{type:"checkbox"}});d.wikiReferences.includes(qe.name)&&(We.checked=!0),at.createSpan({text:` ${qe.name}`,cls:"af-form-checkbox-label"}),We.addEventListener("change",()=>{We.checked?d.wikiReferences.includes(qe.name)||d.wikiReferences.push(qe.name):d.wikiReferences=d.wikiReferences.filter(ze=>ze!==qe.name)})}}}if(a.isFolder){let L=u.createDiv({cls:"af-create-section"}),Y=L.createDiv({cls:"af-create-section-header"}),Te=Y.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Te,"heart-pulse");let Le=Y.createSpan({text:"Heartbeat"});this.addTooltip(Le,"Autonomous periodic run \u2014 what the agent does when no one is asking");let qe=L.createDiv({cls:"af-form-row af-form-row-toggle"});qe.createDiv({cls:"af-form-label",text:"Enabled"});let at=qe.createDiv({cls:`af-agent-card-toggle${d.heartbeatEnabled?" on":""}`}),We=L.createDiv();We.setCssStyles({display:d.heartbeatEnabled?"":"none"}),at.onclick=()=>{let ct=at.hasClass("on");at.toggleClass("on",!ct),d.heartbeatEnabled=!ct,We.setCssStyles({display:ct?"none":""})},this.renderHeartbeatSchedule(We,d);let ze=We.createDiv({cls:"af-form-row af-form-row-toggle"}),Za=ze.createDiv({cls:"af-form-label"});Za.setText("Notify"),this.addTooltip(Za,"Show an Obsidian notice when the heartbeat completes");let Gn=ze.createDiv({cls:`af-agent-card-toggle${d.heartbeatNotify?" on":""}`});Gn.onclick=()=>{let ct=Gn.hasClass("on");Gn.toggleClass("on",!ct),d.heartbeatNotify=!ct};let nl=this.plugin.runtime.getSnapshot(),er=We.createDiv({cls:"af-form-row"}),tr=er.createDiv({cls:"af-form-label"});tr.setText("Post to channel"),this.addTooltip(tr,"Heartbeat results are posted to this Slack channel when the run completes");let Bs=er.createEl("select",{cls:"af-form-select"});Bs.createEl("option",{text:"(none)",attr:{value:""}});for(let ct of nl.channels){let al=Bs.createEl("option",{text:ct.name,attr:{value:ct.name}});ct.name===d.heartbeatChannel&&(al.selected=!0)}Bs.addEventListener("change",()=>{d.heartbeatChannel=Bs.value,nr()});let Vn=We.createDiv({cls:"af-form-row"}),sr=Vn.createDiv({cls:"af-form-label"});sr.setText("Target ID"),this.addTooltip(sr,"Specific channel id to post to (Discord/Slack channel id, Telegram chat id). Empty = DM the channel\u2019s first allowed user.");let Yn=Vn.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Channel/chat id \u2014 empty = DM"}});Yn.value=d.heartbeatChannelTarget,Yn.addEventListener("input",()=>{d.heartbeatChannelTarget=Yn.value.trim()});let nr=()=>{Vn.setCssStyles({display:d.heartbeatChannel?"":"none"})};nr();let Us=We.createDiv({cls:"af-form-label"});Us.setCssStyles({width:"auto"}),Us.setCssStyles({marginTop:"12px"}),Us.setText("Instruction"),this.addTooltip(Us,'What the agent does on each heartbeat. Also used by the "Run Now" button.');let Kn=We.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Check status, scan for issues, report findings...",rows:"8"}});Kn.value=d.heartbeatBody,Kn.addEventListener("input",()=>{d.heartbeatBody=Kn.value})}let ke=u.createDiv({cls:"af-create-section"}),Oe=ke.createDiv({cls:"af-create-section-header"}),Ue=Oe.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Ue,"puzzle"),Oe.createSpan({text:"Skills"});let Ne=this.plugin.runtime.getSnapshot();if(Ne.skills.length>0){ke.createDiv({cls:"af-form-sublabel",text:"Shared Skills"});let L=ke.createDiv({cls:"af-create-skills-grid"});for(let Y of Ne.skills){let Te=L.createDiv({cls:"af-create-skill-item"}),Le=Te.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});Le.checked=d.selectedSkills.has(Y.name),Le.addEventListener("change",()=>{Le.checked?d.selectedSkills.add(Y.name):d.selectedSkills.delete(Y.name)});let qe=Te.createDiv({cls:"af-create-skill-label"});qe.createSpan({cls:"af-create-skill-name",text:Y.name}),Y.description&&qe.createSpan({cls:"af-create-skill-desc",text:` \u2014 ${Y.description}`})}}let q=ke.createDiv({cls:"af-form-sublabel"});q.setText("Agent-specific skills"),this.addTooltip(q,"Custom skills/instructions only for this agent, not shared with others");let re=ke.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Custom skills/instructions for this agent...",rows:"4"}});re.value=a.skillsBody,re.addEventListener("input",()=>{d.skillsBody=re.value});let j=u.createDiv({cls:"af-create-section"}),Ce=j.createDiv({cls:"af-create-section-header"}),xe=Ce.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(xe,"plug");let he=Ce.createSpan({text:"MCP Servers"});this.addTooltip(he,"Grant agent access to MCP servers"),this.renderAgentMcpPicker(j,d.selectedMcpServers);let $e=u.createDiv({cls:"af-create-section"}),ie=$e.createDiv({cls:"af-create-section-header"}),I=ie.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(I,"file-text");let se=ie.createSpan({text:"Context"});this.addTooltip(se,"Project-specific context included in every run");let ce=$e.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:"Background info, repo structure, conventions...",rows:"4"}});ce.value=a.contextBody,ce.addEventListener("input",()=>{d.contextBody=ce.value});let te=u.createDiv({cls:"af-create-section"}),st=te.createDiv({cls:"af-create-section-header"}),ls=st.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(ls,"shield-check"),st.createSpan({text:"Permissions"}),this.createFormField(te,"Approval required","git_push, file_delete","Comma-separated tool names",L=>{d.approvalRequired=L},a.approvalRequired.join(", "));let cs=te.createDiv({cls:"af-form-row"});cs.createDiv({cls:"af-form-label",text:"Allowed Commands"});let ds=cs.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(curl *)
|
|
12024
|
-
Bash(python3 *)
|
|
12025
|
-
Read
|
|
12026
|
-
Edit
|
|
12027
|
-
Write`,rows:"4"}});ds.value=a.permissionRules.allow.join(`
|
|
12028
|
-
`),ds.addEventListener("input",()=>{d.allowedCommands=ds.value});let Bt=te.createDiv({cls:"af-form-row"});Bt.createDiv({cls:"af-form-label",text:"Blocked Commands"});let B=Bt.createEl("textarea",{cls:"af-create-textarea",attr:{placeholder:`Bash(git push *)
|
|
12029
|
-
Bash(rm -rf *)
|
|
12030
|
-
Bash(sudo *)`,rows:"4"}});B.value=a.permissionRules.deny.join(`
|
|
12031
|
-
`),B.addEventListener("input",()=>{d.blockedCommands=B.value}),te.createDiv({cls:"af-form-hint",text:"On Codex agents these become execpolicy command rules \u2014 only Bash(cmd args *) prefixes are enforced; tool-name rules (Read/Write) and mid-pattern wildcards are ignored, and file/network access is governed by Permission Mode (the sandbox)."});let V=te.createDiv({cls:"af-form-row"});V.createDiv({cls:"af-form-label",text:"Memory enabled"});let Ee=V.createDiv({cls:`af-agent-card-toggle${a.memory?" on":""}`});Ee.onclick=()=>{let L=Ee.hasClass("on");Ee.toggleClass("on",!L),d.memory=!L};let we=te.createDiv({cls:"af-form-row"});we.createDiv({cls:"af-form-label",text:"Memory token budget"});let Ae=we.createEl("input",{cls:"af-create-input",attr:{type:"number",min:"200",step:"100"}});Ae.value=String(d.memoryTokenBudget),Ae.addEventListener("input",()=>{let L=parseInt(Ae.value,10);Number.isFinite(L)&&(d.memoryTokenBudget=L)});let nt=te.createDiv({cls:"af-form-row"});nt.createDiv({cls:"af-form-label",text:"Nightly reflection"});let je=nt.createDiv({cls:`af-agent-card-toggle${a.reflection.enabled?" on":""}`});je.onclick=()=>{let L=je.hasClass("on");je.toggleClass("on",!L),d.reflectionEnabled=!L};let Tt=te.createDiv({cls:"af-form-row"});Tt.createDiv({cls:"af-form-label",text:"Propose skills from memory"});let Ut=Tt.createDiv({cls:`af-agent-card-toggle${a.reflection.proposeSkills?" on":""}`});Ut.onclick=()=>{let L=Ut.hasClass("on");Ut.toggleClass("on",!L),d.reflectionProposeSkills=!L};let bt=s.createDiv({cls:"af-create-footer"}),hs=bt.createEl("button",{cls:"af-btn-sm danger"});R(hs,"trash-2","af-btn-icon"),hs.appendText(" Delete"),hs.onclick=()=>void this.plugin.deleteAgent(a.name),bt.createDiv({cls:"af-toolbar-spacer"});let Ns=bt.createEl("button",{cls:"af-btn-sm",text:"Cancel"});Ns.onclick=()=>this.navigate("agent-detail",a.name);let $t=bt.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R($t,"check","af-btn-icon"),$t.appendText(" Save Changes"),$t.onclick=async()=>{let L=Y=>Y.split(",").map(Te=>Te.trim()).filter(Boolean);try{let Y=Te=>ye(Te).map(Le=>Le.trim()).filter(Boolean);await this.plugin.repository.updateAgent(a.name,{description:d.description.trim(),avatar:d.avatar.trim(),tags:L(d.tags),systemPrompt:d.systemPrompt.trim(),model:d.model.trim()||"default",adapter:d.adapter,cwd:d.cwd.trim(),timeout:d.timeout,permissionMode:d.permissionMode,effort:d.effort||void 0,approvalRequired:L(d.approvalRequired),memory:d.memory,memoryTokenBudget:d.memoryTokenBudget,reflectionEnabled:d.reflectionEnabled,reflectionProposeSkills:d.reflectionProposeSkills,skills:Array.from(d.selectedSkills),mcpServers:Array.from(d.selectedMcpServers),skillsBody:d.skillsBody.trim(),contextBody:d.contextBody.trim(),enabled:d.enabled,permissionRules:{allow:Y(d.allowedCommands),deny:Y(d.blockedCommands)},autoCompactThreshold:d.autoCompactThreshold,wikiReferences:d.wikiReferences}),a.isFolder&&await this.plugin.repository.updateHeartbeat(a.name,{enabled:d.heartbeatEnabled,schedule:d.heartbeatSchedule.trim(),notify:d.heartbeatNotify,channel:d.heartbeatChannel,channelTarget:d.heartbeatChannel?d.heartbeatChannelTarget:"",body:d.heartbeatBody.trim()}),new b.Notice(`Agent "${a.name}" updated.`),await this.plugin.refreshFromVault(),this.navigate("agent-detail",a.name)}catch(Y){let Te=Y instanceof Error?Y.message:String(Y);new b.Notice(`Failed to update agent: ${Te}`)}}}renderTaskChannelDelivery(e,s,n){let a=e.createDiv({cls:"af-form-row"}),i=a.createDiv({cls:"af-form-label",text:"Channel"}),o=a.createEl("select",{cls:"af-form-select"});o.createEl("option",{text:"\u2014 none (run log only) \u2014",attr:{value:""}});for(let u of s){let p=o.createEl("option",{text:u.name,attr:{value:u.name}});u.name===n.channel&&(p.selected=!0)}this.addTooltip(i,"Post this task\u2019s full output to a channel when it finishes. Leave as none to only write the run log (the default batched behavior).");let c=e.createDiv({cls:"af-form-row"}),l=c.createDiv({cls:"af-form-label",text:"Target ID"}),h=c.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:"Discord/Slack channel ID or Telegram chat ID \u2014 empty = DM you"}});h.value=n.channelTarget,h.addEventListener("input",()=>{n.channelTarget=h.value.trim()}),this.addTooltip(l,"Where in the channel to post. For Discord, enable Developer Mode and right-click the channel \u2192 Copy Channel ID. Leave empty to DM the first allowed user instead.");let d=()=>{c.setCssStyles({display:n.channel?"":"none"})};d(),o.addEventListener("change",()=>{n.channel=o.value,d()})}renderCreateTaskPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=this.plugin.runtime.getSnapshot(),a=s.createDiv({cls:"af-detail-header"}),i=a.createDiv({cls:"af-detail-header-left"}),o=i.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(o,"plus");let c=i.createDiv();c.createDiv({cls:"af-detail-header-name",text:"Create New Task"}),c.createDiv({cls:"af-detail-header-desc",text:"Configure a new task for your fleet"});let l=a.createDiv({cls:"af-detail-header-actions"}),h={title:"",agent:n.agents[0]?.name??"",priority:"medium",tags:"",body:"",scheduleEnabled:!1,scheduleMode:"recurring",schedule:"0 9 * * *",runAt:"",type:"immediate",enabled:!0,catchUp:!0,effort:"",model:"",channel:"",channelTarget:""},d=s.createDiv({cls:"af-create-form"}),u=d.createDiv({cls:"af-create-section"}),p=u.createDiv({cls:"af-create-section-header"}),m=p.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(m,"file-text"),p.createSpan({text:"Task Details"}),this.createFormField(u,"Title","Daily status report","Used as the task identifier",q=>{h.title=q});let f=u.createDiv({cls:"af-form-row"});f.createDiv({cls:"af-form-label",text:"Agent"});let g=f.createEl("select",{cls:"af-form-select"});for(let q of n.agents)g.createEl("option",{text:q.name,attr:{value:q.name}});g.addEventListener("change",()=>{h.agent=g.value});let y=u.createDiv({cls:"af-form-row"});y.createDiv({cls:"af-form-label",text:"Priority"});let v=y.createEl("select",{cls:"af-form-select"}),k=[["low","Low"],["medium","Medium"],["high","High"],["critical","Critical"]];for(let[q,re]of k){let j=v.createEl("option",{text:re,attr:{value:q}});q==="medium"&&(j.selected=!0)}v.addEventListener("change",()=>{h.priority=v.value}),this.createFormField(u,"Tags","monitoring, devops","Comma-separated",q=>{h.tags=q});let w=d.createDiv({cls:"af-create-section"}),S=w.createDiv({cls:"af-create-section-header"}),T=S.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(T,"message-square"),S.createSpan({text:"Instructions"});let _=w.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Describe what the agent should do...",rows:"10"}});_.addEventListener("input",()=>{h.body=_.value});let D=d.createDiv({cls:"af-create-section"}),O=D.createDiv({cls:"af-create-section-header"}),C=O.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(C,"clock"),O.createSpan({text:"Schedule"});let E=D.createDiv({cls:"af-form-row af-form-row-toggle"});E.createDiv({cls:"af-form-label",text:"Enable schedule"});let P=E.createDiv({cls:"af-agent-card-toggle"}),N=D.createDiv({cls:"af-schedule-body"});N.setCssStyles({display:"none"}),P.onclick=()=>{let q=P.hasClass("on");P.toggleClass("on",!q),h.scheduleEnabled=!q,N.setCssStyles({display:q?"none":""}),q?h.type="immediate":h.type=h.scheduleMode==="once"?"once":"recurring"};let M=N.createDiv({cls:"af-form-row"});M.createDiv({cls:"af-form-label",text:"Mode"});let U=M.createEl("select",{cls:"af-form-select"});for(let[q,re]of[["recurring","Recurring"],["once","One-time"]])U.createEl("option",{text:re,attr:{value:q}});let $=N.createDiv(),Z=N.createDiv();Z.setCssStyles({display:"none"}),this.renderInlineSchedule($,h);let de=Z.createDiv({cls:"af-form-row"});de.createDiv({cls:"af-form-label",text:"Run at"});let me=de.createEl("input",{cls:"af-form-input",attr:{type:"datetime-local",value:this.toDatetimeLocal(new Date(Date.now()+36e5))}});h.runAt=new Date(me.value).toISOString(),me.addEventListener("input",()=>{h.runAt=me.value?new Date(me.value).toISOString():""}),U.addEventListener("change",()=>{h.scheduleMode=U.value,$.setCssStyles({display:h.scheduleMode==="recurring"?"":"none"}),Z.setCssStyles({display:h.scheduleMode==="once"?"":"none"}),h.scheduleEnabled&&(h.type=h.scheduleMode==="once"?"once":"recurring")});let ge=N.createDiv({cls:"af-form-row af-form-row-toggle"});ge.createDiv({cls:"af-form-label",text:"Enabled"});let X=ge.createDiv({cls:"af-agent-card-toggle on"});X.onclick=()=>{let q=X.hasClass("on");X.toggleClass("on",!q),h.enabled=!q};let W=N.createDiv({cls:"af-form-row af-form-row-toggle"});W.createDiv({cls:"af-form-label"}).setText("Catch up if missed");let ne=W.createDiv({cls:`af-agent-card-toggle${h.catchUp?" on":""}`});ne.onclick=()=>{let q=ne.hasClass("on");ne.toggleClass("on",!q),h.catchUp=!q};let G=d.createDiv({cls:"af-create-section"}),ee=G.createDiv({cls:"af-create-section-header"}),Q=ee.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Q,"gauge"),ee.createSpan({text:"Execution"});let ae=G.createDiv({cls:"af-form-row"}),ve=ae.createDiv({cls:"af-form-label",text:"Model"}),Pe=ae.createDiv({cls:"af-form-field-wrap"}),Ie=q=>{Pe.empty();let re=n.agents.find(j=>j.name===q);Rt(Pe,{value:h.model,adapter:re?.adapter,onChange:j=>{h.model=j},allowInherit:!0,inheritPlaceholder:re?`Inherit from ${re.name}${re.model?` (${re.model})`:""}`:"Inherit from agent"})};Ie(h.agent),g.addEventListener("change",()=>Ie(g.value)),this.addTooltip(ve,"Override the agent\u2019s model for this task only. Useful for routing simple runs to haiku while the agent stays on opus for heavier work.");let Me=G.createDiv({cls:"af-form-row"}),Fe=Me.createDiv({cls:"af-form-label",text:"Effort"}),ke=Me.createEl("select",{cls:"af-form-select"});for(let[q,re]of[["","Agent Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]]){let j=ke.createEl("option",{text:re,attr:{value:q}});q===h.effort&&(j.selected=!0)}ke.addEventListener("change",()=>{h.effort=ke.value}),this.renderTaskChannelDelivery(G,n.channels,h),this.addTooltip(Fe,"Overrides the agent\u2019s effort level for this task. Higher effort = more thinking tokens spent.");let Oe=s.createDiv({cls:"af-create-footer"}),Ue=Oe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});Ue.onclick=()=>this.navigate("kanban");let Ne=Oe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(Ne,"plus","af-btn-icon"),Ne.appendText(" Create Task"),Ne.onclick=async()=>{let q=h.title.trim();if(!q){new b.Notice("Task title is required.");return}let re=oe(q),j=he=>he.split(",").map($e=>$e.trim()).filter(Boolean),Ce=h.scheduleEnabled?h.scheduleMode==="once"?"once":"recurring":"immediate",xe={task_id:re,agent:h.agent,type:Ce,priority:h.priority,enabled:h.enabled,created:this.toLocalISO(new Date),run_count:0,catch_up:h.catchUp,effort:h.effort||void 0,model:h.model||void 0,channel:h.channel||void 0,channel_target:h.channel&&h.channelTarget?h.channelTarget:void 0,tags:j(h.tags)};if(Ce==="recurring")xe.schedule=h.schedule.trim()||"0 9 * * *";else if(Ce==="once"){if(!h.runAt){new b.Notice("Pick a date/time for the one-time run.");return}xe.run_at=h.runAt}try{let he=await this.plugin.repository.getAvailablePath(this.plugin.repository.getSubfolder("tasks"),re);await this.plugin.app.vault.create(he,H(xe,h.body.trim()||"Describe the task here.")),new b.Notice(`Task "${re}" created.`),await this.plugin.refreshFromVault(),this.navigate("task-detail",re)}catch(he){let $e=he instanceof Error?he.message:String(he);new b.Notice(`Failed to create task: ${$e}`)}}}toLocalISO(e){let s=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${s(e.getMonth()+1)}-${s(e.getDate())}T${s(e.getHours())}:${s(e.getMinutes())}:${s(e.getSeconds())}`}toDatetimeLocal(e){let s=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${s(e.getMonth()+1)}-${s(e.getDate())}T${s(e.getHours())}:${s(e.getMinutes())}`}renderEditTaskPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"circle-dot","No task selected","");return}let a=this.plugin.runtime.getSnapshot().tasks.find(I=>I.taskId===n);if(!a){this.renderEmptyState(s,"circle-dot","Task not found",`Task "${n}" was not found`);return}let i=this.plugin.runtime.getSnapshot(),o=s.createDiv({cls:"af-detail-header"}),c=o.createDiv({cls:"af-detail-header-left"}),l=c.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(l,"edit");let h=c.createDiv();h.createDiv({cls:"af-detail-header-name",text:`Edit Task: ${a.taskId}`}),h.createDiv({cls:"af-detail-header-desc",text:"Modify task configuration"});let d=o.createDiv({cls:"af-detail-header-actions"}),u=!!(a.schedule||a.runAt),p={agent:a.agent,type:a.type,priority:a.priority,schedule:a.schedule??"0 9 * * *",runAt:a.runAt??"",scheduleEnabled:u,scheduleMode:a.type==="once"?"once":"recurring",enabled:a.enabled,catchUp:a.catchUp,effort:a.effort??"",model:a.model??"",channel:a.channel??"",channelTarget:a.channelTarget??"",tags:a.tags.join(", "),body:a.body},m=s.createDiv({cls:"af-create-form"}),f=m.createDiv({cls:"af-create-section"}),g=f.createDiv({cls:"af-create-section-header"}),y=g.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(y,"file-text"),g.createSpan({text:"Task Details"});let v=f.createDiv({cls:"af-form-row"});v.createDiv({cls:"af-form-label",text:"Title"}),v.createEl("input",{cls:"af-form-input",attr:{type:"text",value:a.taskId,disabled:"true"}}).setCssStyles({opacity:"0.6"});let w=f.createDiv({cls:"af-form-row"});w.createDiv({cls:"af-form-label",text:"Agent"});let S=w.createEl("select",{cls:"af-form-select"});for(let I of i.agents){let se=S.createEl("option",{text:I.name,attr:{value:I.name}});I.name===a.agent&&(se.selected=!0)}S.addEventListener("change",()=>{p.agent=S.value});let T=f.createDiv({cls:"af-form-row"});T.createDiv({cls:"af-form-label",text:"Priority"});let _=T.createEl("select",{cls:"af-form-select"}),D=[["low","Low"],["medium","Medium"],["high","High"],["critical","Critical"]];for(let[I,se]of D){let ce=_.createEl("option",{text:se,attr:{value:I}});I===a.priority&&(ce.selected=!0)}_.addEventListener("change",()=>{p.priority=_.value}),this.createFormField(f,"Tags","monitoring, critical","Comma-separated",I=>{p.tags=I},a.tags.join(", "));let O=m.createDiv({cls:"af-create-section"}),C=O.createDiv({cls:"af-create-section-header"}),E=C.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(E,"message-square"),C.createSpan({text:"Instructions"});let P=O.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Describe what the agent should do...",rows:"10"}});P.value=a.body,P.addEventListener("input",()=>{p.body=P.value});let N=m.createDiv({cls:"af-create-section"}),M=N.createDiv({cls:"af-create-section-header"}),U=M.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(U,"clock"),M.createSpan({text:"Schedule"});let $=N.createDiv({cls:"af-form-row af-form-row-toggle"});$.createDiv({cls:"af-form-label",text:"Enable schedule"});let Z=$.createDiv({cls:`af-agent-card-toggle${u?" on":""}`}),de=N.createDiv({cls:"af-schedule-body"});de.setCssStyles({display:u?"":"none"}),Z.onclick=()=>{let I=Z.hasClass("on");Z.toggleClass("on",!I),p.scheduleEnabled=!I,de.setCssStyles({display:I?"none":""}),I?p.type="immediate":p.type=p.scheduleMode==="once"?"once":"recurring"};let me=de.createDiv({cls:"af-form-row"});me.createDiv({cls:"af-form-label",text:"Mode"});let ge=me.createEl("select",{cls:"af-form-select"});for(let[I,se]of[["recurring","Recurring"],["once","One-time"]]){let ce=ge.createEl("option",{text:se,attr:{value:I}});I===p.scheduleMode&&(ce.selected=!0)}let X=de.createDiv(),W=de.createDiv();X.setCssStyles({display:p.scheduleMode==="recurring"?"":"none"}),W.setCssStyles({display:p.scheduleMode==="once"?"":"none"}),this.renderInlineSchedule(X,p);let K=W.createDiv({cls:"af-form-row"});K.createDiv({cls:"af-form-label",text:"Run at"});let ne=p.runAt?this.toDatetimeLocal(new Date(p.runAt)):this.toDatetimeLocal(new Date(Date.now()+36e5)),G=K.createEl("input",{cls:"af-form-input",attr:{type:"datetime-local",value:ne}});p.runAt||(p.runAt=new Date(G.value).toISOString()),G.addEventListener("input",()=>{p.runAt=G.value?new Date(G.value).toISOString():""}),ge.addEventListener("change",()=>{p.scheduleMode=ge.value,X.setCssStyles({display:p.scheduleMode==="recurring"?"":"none"}),W.setCssStyles({display:p.scheduleMode==="once"?"":"none"}),p.scheduleEnabled&&(p.type=p.scheduleMode==="once"?"once":"recurring")});let ee=de.createDiv({cls:"af-form-row af-form-row-toggle"});ee.createDiv({cls:"af-form-label",text:"Enabled"});let Q=ee.createDiv({cls:`af-agent-card-toggle${a.enabled?" on":""}`});Q.onclick=()=>{let I=Q.hasClass("on");Q.toggleClass("on",!I),p.enabled=!I};let ae=de.createDiv({cls:"af-form-row af-form-row-toggle"});ae.createDiv({cls:"af-form-label"}).setText("Catch up if missed");let Pe=ae.createDiv({cls:`af-agent-card-toggle${p.catchUp?" on":""}`});Pe.onclick=()=>{let I=Pe.hasClass("on");Pe.toggleClass("on",!I),p.catchUp=!I};let Ie=m.createDiv({cls:"af-create-section"}),Me=Ie.createDiv({cls:"af-create-section-header"}),Fe=Me.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(Fe,"gauge"),Me.createSpan({text:"Execution"});let ke=Ie.createDiv({cls:"af-form-row"}),Oe=ke.createDiv({cls:"af-form-label",text:"Effort"}),Ue=ke.createEl("select",{cls:"af-form-select"}),Ne=[["","Agent Default"],["low","Low"],["medium","Medium"],["high","High"],["max","Max"]];for(let[I,se]of Ne){let ce=Ue.createEl("option",{text:se,attr:{value:I}});I===p.effort&&(ce.selected=!0)}Ue.addEventListener("change",()=>{p.effort=Ue.value}),this.addTooltip(Oe,"Overrides the agent\u2019s effort level for this task. Higher effort = more thinking tokens spent.");let q=Ie.createDiv({cls:"af-form-row"}),re=q.createDiv({cls:"af-form-label",text:"Model"}),j=q.createDiv({cls:"af-form-field-wrap"}),Ce=I=>{j.empty();let se=i.agents.find(ce=>ce.name===I);Rt(j,{value:p.model,adapter:se?.adapter,onChange:ce=>{p.model=ce},allowInherit:!0,inheritPlaceholder:se?`Inherit from ${se.name}${se.model?` (${se.model})`:""}`:"Inherit from agent"})};Ce(p.agent),S.addEventListener("change",()=>Ce(S.value)),this.renderTaskChannelDelivery(Ie,i.channels,p),this.addTooltip(re,"Override the agent\u2019s model for this task only. Useful for routing simple runs to haiku while the agent stays on opus for heavier work.");let xe=s.createDiv({cls:"af-create-footer"}),he=xe.createEl("button",{cls:"af-btn-sm danger"});R(he,"trash-2","af-btn-icon"),he.appendText(" Delete"),he.onclick=async()=>{await this.plugin.repository.deleteTask(a.taskId),new b.Notice(`Task "${a.taskId}" deleted.`),await new Promise(I=>window.setTimeout(I,200)),await this.plugin.refreshFromVault(),this.navigate("kanban")},xe.createDiv({cls:"af-toolbar-spacer"});let $e=xe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});$e.onclick=()=>this.navigate("task-detail",a.taskId);let ie=xe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(ie,"check","af-btn-icon"),ie.appendText(" Save Changes"),ie.onclick=async()=>{let I=ce=>ce.split(",").map(te=>te.trim()).filter(Boolean),se=p.scheduleEnabled?p.scheduleMode==="once"?"once":"recurring":"immediate";if(se==="once"&&!p.runAt){new b.Notice("Pick a date/time for the one-time run.");return}try{await this.plugin.repository.updateTask(a.taskId,{agent:p.agent,type:se,priority:p.priority,schedule:se==="recurring"?p.schedule.trim():"",runAt:se==="once"?p.runAt:"",enabled:p.enabled,catch_up:p.catchUp,effort:p.effort||void 0,model:p.model||"",channel:p.channel||"",channelTarget:p.channel&&p.channelTarget?p.channelTarget:"",tags:I(p.tags),body:p.body.trim()}),new b.Notice(`Task "${a.taskId}" updated.`),await this.plugin.refreshFromVault(),this.navigate("task-detail",a.taskId)}catch(ce){let te=ce instanceof Error?ce.message:String(ce);new b.Notice(`Failed to update task: ${te}`)}}}renderEditSkillPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"puzzle","No skill selected","");return}let a=this.plugin.runtime.getSnapshot().skills.find(G=>G.name===n);if(!a){this.renderEmptyState(s,"puzzle","Skill not found",`Skill "${n}" was not found`);return}let i=s.createDiv({cls:"af-detail-header"}),o=i.createDiv({cls:"af-detail-header-left"}),c=o.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(c,"edit");let l=o.createDiv();l.createDiv({cls:"af-detail-header-name",text:`Edit Skill: ${a.name}`}),l.createDiv({cls:"af-detail-header-desc",text:"Modify skill definition"});let h=i.createDiv({cls:"af-detail-header-actions"}),d={description:a.description??"",tags:a.tags.join(", "),body:a.body,toolsBody:a.toolsBody,referencesBody:a.referencesBody,examplesBody:a.examplesBody},u=s.createDiv({cls:"af-create-form"}),p=u.createDiv({cls:"af-create-section"}),m=p.createDiv({cls:"af-create-section-header"}),f=m.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(f,"puzzle"),m.createSpan({text:"Identity"});let g=p.createDiv({cls:"af-form-row"});g.createDiv({cls:"af-form-label",text:"Name"}),g.createEl("input",{cls:"af-form-input",attr:{type:"text",value:a.name,disabled:"true"}}).setCssStyles({opacity:"0.6"}),this.createFormField(p,"Description","Manage tasks and projects via CLI","",G=>{d.description=G},a.description??""),this.createFormField(p,"Tags","productivity, tasks","Comma-separated",G=>{d.tags=G},a.tags.join(", "));let v=u.createDiv({cls:"af-create-section"}),k=v.createDiv({cls:"af-create-section-header"}),w=k.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(w,"file-text"),k.createSpan({text:"Core Instructions"});let S=v.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"Skill instructions...",rows:"10"}});S.value=a.body,S.addEventListener("input",()=>{d.body=S.value});let T=u.createDiv({cls:"af-create-section"}),_=T.createDiv({cls:"af-create-section-header"}),D=_.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(D,"wrench");let O=_.createSpan({text:"Tools"});this.addTooltip(O,"CLI commands, API endpoints, and tool definitions available to agents using this skill");let C=T.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`## Commands
|
|
12017
|
+
Agent: ...`,rows:"6"}});t&&(oe.value=t.examplesBody),oe.addEventListener("input",()=>{l.examplesBody=oe.value});let be=a.createDiv({cls:"af-create-footer"});if(t){let H=be.createEl("button",{cls:"af-btn-sm danger"});T(H,"trash-2","af-btn-icon"),H.appendText(" Delete"),H.onclick=()=>{new ut(s.app,{title:`Delete skill "${t.name}"?`,body:"The skill file will be moved to your system trash and can be recovered.",confirmText:"Delete",danger:!0,onConfirm:async()=>{await s.repository.deleteSkill(t.name),new Ve.Notice(`Skill "${t.name}" deleted.`),await new Promise(X=>window.setTimeout(X,200)),await s.refreshFromVault(),e.navigate("skills")}}).open()},be.createDiv({cls:"af-toolbar-spacer"})}let ne=be.createEl("button",{cls:"af-btn-sm",text:"Cancel"});ne.onclick=()=>e.navigate("skills");let Y=be.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(Y,t?"check":"plus","af-btn-icon"),Y.appendText(t?" Save Changes":" Create Skill"),t?Y.onclick=async()=>{let H=me=>me.split(",").map(ee=>ee.trim()).filter(Boolean),X=e.markSubmitBusy(Y,"Saving...","check","Save Changes");try{await s.repository.updateSkill(t.name,{description:l.description.trim(),tags:H(l.tags),body:l.body.trim(),toolsBody:l.toolsBody.trim(),referencesBody:l.referencesBody.trim(),examplesBody:l.examplesBody.trim()}),new Ve.Notice(`Skill "${t.name}" updated.`),await s.refreshFromVault(),e.navigate("skills")}catch(me){let ee=me instanceof Error?me.message:String(me);new Ve.Notice(`Failed to update skill: ${ee}`),X()}}:Y.onclick=async()=>{let H=l.name.trim();if(!H){new Ve.Notice("Skill name is required.");return}let X=z(H);if(s.repository.getSkillByName(X)){new Ve.Notice(`Skill "${X}" already exists.`);return}let me=J=>J.split(",").map(K=>K.trim()).filter(Boolean),ee=e.markSubmitBusy(Y,"Creating...","plus","Create Skill");try{await s.repository.createSkillFolder({name:X,description:l.description.trim(),tags:me(l.tags),body:l.body.trim(),toolsBody:l.toolsBody.trim(),referencesBody:l.referencesBody.trim(),examplesBody:l.examplesBody.trim()}),new Ve.Notice(`Skill "${X}" created.`),await s.refreshFromVault(),e.navigate("skills")}catch(J){let K=J instanceof Error?J.message:String(J);new Ve.Notice(`Failed to create skill: ${K}`),ee()}}}var Ye=require("obsidian");function cc(a,e){let{plugin:t}=e,s=a.createDiv({cls:"af-detail-header"}),n=s.createDiv({cls:"af-detail-header-left"}),r=n.createDiv({cls:"af-agent-card-avatar idle"});(0,Ye.setIcon)(r,"plus");let i=n.createDiv();i.createDiv({cls:"af-detail-header-name",text:"Add MCP Server"}),i.createDiv({cls:"af-detail-header-desc",text:"Register a new MCP server for agents to use"}),s.createDiv({cls:"af-detail-header-actions"});let o={name:"",transport:"stdio",description:"",command:"",args:"",envVars:"",url:"",headers:"",auth:"none",bearerToken:""},l=a.createDiv({cls:"af-create-form"}),c=l.createDiv({cls:"af-create-section"}),d=c.createDiv({cls:"af-create-section-header"}),u=d.createSpan({cls:"af-create-section-icon"});(0,Ye.setIcon)(u,"plug"),d.createSpan({text:"Server Details"}),e.createFormField(c,"Name","my-server","Unique name for this MCP server",Y=>{o.name=Y});let h=c.createDiv({cls:"af-form-row"}),p=h.createDiv({cls:"af-form-label"});p.setText("Transport"),e.addTooltip(p,"stdio: local process, http/sse: remote server");let m=h.createEl("select",{cls:"af-form-select"});m.createEl("option",{text:"stdio",attr:{value:"stdio"}}),m.createEl("option",{text:"http",attr:{value:"http"}}),m.createEl("option",{text:"sse",attr:{value:"sse"}}),e.createFormField(c,"Description","What this server does (optional)","Shown on the server card",Y=>{o.description=Y});let f=l.createDiv({cls:"af-create-section"}),g=f.createDiv({cls:"af-create-section-header"}),w=g.createSpan({cls:"af-create-section-icon"});(0,Ye.setIcon)(w,"terminal"),g.createSpan({text:"Process Configuration"}),e.createFormField(f,"Command","npx @anthropic-ai/mcp-server-memory","The command to run",Y=>{o.command=Y}),e.createFormField(f,"Arguments","--port 3000","Space-separated arguments (optional)",Y=>{o.args=Y});let y=f.createDiv({cls:"af-form-label"});y.setText("Environment variables"),e.addTooltip(y,"One KEY=VALUE per line");let v=f.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`API_KEY=sk-...
|
|
12018
|
+
DEBUG=true`,rows:"3"}});v.addEventListener("input",()=>{o.envVars=v.value});let k=l.createDiv({cls:"af-create-section"}),b=k.createDiv({cls:"af-create-section-header"}),P=b.createSpan({cls:"af-create-section-icon"});(0,Ye.setIcon)(P,"globe"),b.createSpan({text:"Remote Server Configuration"}),e.createFormField(k,"URL","https://mcp.example.com/sse","Server endpoint URL",Y=>{o.url=Y});let A=k.createDiv({cls:"af-form-label"});A.setText("Custom headers"),e.addTooltip(A,"One Header: Value per line (optional, non-secret)");let M=k.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"X-Custom-Header: value",rows:"2"}});M.addEventListener("input",()=>{o.headers=M.value});let E=k.createDiv({cls:"af-form-row"}),x=E.createDiv({cls:"af-form-label"});x.setText("Authentication"),e.addTooltip(x,"none, a static bearer token, or OAuth (authenticate after saving)");let _=E.createEl("select",{cls:"af-form-select"});_.createEl("option",{text:"None",attr:{value:"none"}}),_.createEl("option",{text:"Bearer token",attr:{value:"bearer"}}),_.createEl("option",{text:"OAuth",attr:{value:"oauth"}});let R=k.createDiv({cls:"af-form-row"}),O=R.createDiv({cls:"af-form-label"});O.setText("Bearer token"),e.addTooltip(O,"Stored securely in the OS keychain, never written to the vault");let F=R.createEl("input",{cls:"af-form-input",attr:{type:"password",placeholder:"sk-\u2026"}});F.addEventListener("input",()=>{o.bearerToken=F.value});let B=()=>{R.setCssStyles({display:o.auth==="bearer"?"":"none"})};_.addEventListener("change",()=>{o.auth=_.value,B()}),B();let q=()=>{f.setCssStyles({display:o.transport==="stdio"?"":"none"}),k.setCssStyles({display:o.transport!=="stdio"?"":"none"})};m.addEventListener("change",()=>{o.transport=m.value,q()}),q();let oe=a.createDiv({cls:"af-create-footer"}),be=oe.createEl("button",{cls:"af-btn-sm",text:"Cancel"});be.onclick=()=>e.navigate("mcp");let ne=oe.createEl("button",{cls:"af-btn-sm primary af-create-submit"});T(ne,"plus","af-btn-icon"),ne.appendText(" Add Server"),ne.onclick=async()=>{let Y=o.name.trim();if(!Y){new Ye.Notice("Server name is required.");return}if(o.transport==="stdio"){if(!o.command.trim()){new Ye.Notice("Command is required for stdio servers.");return}}else if(!o.url.trim()){new Ye.Notice("URL is required for HTTP/SSE servers.");return}let H={};if(o.envVars.trim())for(let J of re(o.envVars)){let K=J.trim();if(!K)continue;let ke=K.indexOf("=");if(ke<=0){new Ye.Notice(`Invalid env var: ${K}`);return}H[K.slice(0,ke)]=K.slice(ke+1)}let X={};if(o.headers.trim())for(let J of re(o.headers)){let K=J.trim();if(!K)continue;let ke=K.indexOf(":");if(ke<=0){new Ye.Notice(`Invalid header: ${K}`);return}X[K.slice(0,ke).trim()]=K.slice(ke+1).trim()}let me=o.args.trim()?o.args.trim().split(/\s+/):void 0;if(t.repository.getMcpServerByName(Y)){new Ye.Notice(`An MCP server named "${Y}" already exists.`);return}if(o.transport!=="stdio"&&o.auth==="bearer"&&!o.bearerToken.trim()){new Ye.Notice("Enter a bearer token, or choose a different auth method.");return}ne.disabled=!0,ne.setText("Adding...");let ee={name:Y,type:o.transport,enabled:!0,source:"manual",status:"disconnected",scope:"user",tools:[],toolDetails:[]};o.transport==="stdio"?(ee.command=o.command.trim(),me&&(ee.args=me),Object.keys(H).length>0&&(ee.env=H)):(ee.url=o.url.trim(),Object.keys(X).length>0&&(ee.headers=X),ee.auth=o.auth);try{await t.repository.saveMcpServer(ee,o.description.trim()),o.transport!=="stdio"&&o.auth==="bearer"&&o.bearerToken.trim()&&t.mcpAuth.storeStaticToken(Y,o.bearerToken.trim()),new Ye.Notice(`Server "${Y}" added.`),await t.refreshFromVault(),e.navigate("mcp")}catch(J){let K=J instanceof Error?J.message:String(J);new Ye.Notice(`Failed to add server: ${K}`),ne.disabled=!1,ne.setText(""),T(ne,"plus","af-btn-icon"),ne.appendText(" Add Server")}}}var ln=require("obsidian");function dc(a,e){let t=a.createDiv({cls:"af-agents-page"}),s=e.plugin.runtime.getSnapshot(),n=t.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"Agents"}),n.createDiv({cls:"af-toolbar-spacer"});let r=n.createEl("button",{cls:"af-btn-sm primary"});T(r,"plus","af-btn-icon"),r.appendText(" New Agent"),r.onclick=()=>void e.plugin.createAgentTemplate();let i=t.createDiv({cls:"af-agents-grid"});if(s.agents.length===0){e.renderEmptyState(i,"bot","No agents configured","Create your first agent to get started",{label:"New Agent",onClick:()=>void e.plugin.createAgentTemplate()});return}let o=new Map;for(let l of e.plugin.runtime.getRecentRuns()){let c=o.get(l.agent);c?c.push(l):o.set(l.agent,[l])}for(let l of s.agents)ep(i,e,l,s,o.get(l.name)??[])}function ep(a,e,t,s,n){let r=e.plugin.runtime.getAgentState(t.name),i=a.createDiv({cls:`af-agent-card${t.enabled?"":" disabled"}`}),o=i.createDiv({cls:"af-agent-card-header"}),l=t.enabled?e.healthToClass(r.status):"disabled",c=o.createDiv({cls:`af-agent-card-avatar ${l}`});e.renderAgentAvatar(c,t);let d=o.createDiv({cls:"af-agent-card-titleblock"}),u=d.createDiv({cls:"af-agent-card-name"});if(u.appendText(t.name),t.heartbeatEnabled&&t.heartbeatSchedule){let A=u.createSpan({cls:"af-heartbeat-indicator"});(0,ln.setIcon)(A,"heart-pulse"),A.title=`Heartbeat: ${t.heartbeatSchedule}`}d.createDiv({cls:"af-agent-card-desc",text:t.description??"No description"});let h=o.createDiv({cls:`af-agent-card-toggle${t.enabled?" on":""}`});h.onclick=A=>{A.stopPropagation(),e.plugin.toggleAgent(t.name,!t.enabled)};let p=i.createDiv({cls:"af-agent-card-stats"}),m=n.length,f=n.filter(A=>A.status==="success").length,g=m>0?Math.round(f/m*100):0,w=m>0?Math.round(n.reduce((A,M)=>A+M.durationSeconds,0)/m):0,y=n.reduce((A,M)=>A+(M.tokensUsed??0),0);if(e.renderAgentStat(p,String(m),"Runs"),e.renderAgentStat(p,`${g}%`,"Success"),e.renderAgentStat(p,`${w}s`,"Avg Time"),e.renderAgentStat(p,e.formatTokenCount(y),"Tokens"),t.skills.length>0){let A=i.createDiv({cls:"af-agent-card-skills"});for(let M of t.skills)A.createSpan({cls:"af-skill-tag",text:M})}if(t.isFolder&&(t.heartbeatBody.trim()||t.heartbeatEnabled)){let A=i.createDiv({cls:"af-agent-card-heartbeat"}),M=A.createSpan({cls:"af-agent-card-hb-icon"});(0,ln.setIcon)(M,"heart-pulse");let E=[e.cronToHuman(t.heartbeatSchedule)];if(t.heartbeatEnabled){let _=e.plugin.runtime.getNextHeartbeat(t.name);_&&E.push(`next ${e.timeUntil(_)}`)}else E.push("paused");A.createSpan({cls:"af-agent-card-hb-text",text:`Heartbeat \xB7 ${E.join(" \xB7 ")}`});let x=A.createDiv({cls:`af-agent-card-toggle af-agent-card-toggle-sm${t.heartbeatEnabled?" on":""}`});x.title=t.heartbeatEnabled?"Pause heartbeat":"Enable heartbeat",x.onclick=_=>{_.stopPropagation(),(async()=>(await e.plugin.repository.updateHeartbeat(t.name,{enabled:!t.heartbeatEnabled}),await e.plugin.refreshFromVault(),new ln.Notice(`Heartbeat ${t.heartbeatEnabled?"paused":"enabled"} for ${t.name}`)))()}}let v=i.createDiv({cls:"af-agent-card-footer"}),k=[`Model: ${t.model}`];t.approvalRequired.length>0&&k.push(`Approval: ${t.approvalRequired.join(", ")}`),t.memory&&k.push("Memory: on"),t.enabled||k.unshift("Disabled"),v.createSpan({cls:"af-agent-card-meta",text:k.join(" \xB7 ")});let b=v.createDiv({cls:"af-agent-card-actions"});if(!t.enabled){let A=b.createEl("button",{cls:"af-btn-sm",text:"Enable"});A.onclick=M=>{M.stopPropagation(),e.plugin.toggleAgent(t.name,!0)}}let P=b.createEl("button",{cls:"af-btn-sm"});if(T(P,"edit","af-btn-icon"),P.appendText(" Edit"),P.onclick=A=>{A.stopPropagation(),e.navigate("edit-agent",t.name)},t.enabled){let A=b.createEl("button",{cls:"af-btn-sm primary"});T(A,"play","af-btn-icon"),A.appendText(" Run"),A.onclick=M=>{M.stopPropagation(),e.plugin.runAgentPrompt(t.name)}}i.onclick=()=>e.navigate("agent-detail",t.name)}var cn=require("obsidian");function uc(a,e,t){let s=a.createDiv({cls:"af-agent-detail-page"});if(!t){e.renderEmptyState(s,"bot","No agent selected","Select an agent from the list");return}let n=e.plugin.runtime.getSnapshot().agents.find(y=>y.name===t);if(!n){e.renderEmptyState(s,"bot","Agent not found",`Agent "${t}" was not found`);return}let r=e.plugin.runtime.getAgentState(n.name),i=e.plugin.runtime.getRecentRuns().filter(y=>y.agent===n.name),o=s.createDiv({cls:"af-detail-header"}),l=o.createDiv({cls:"af-detail-header-left"}),c=l.createDiv({cls:`af-agent-card-avatar ${e.healthToClass(r.status)}`});e.renderAgentAvatar(c,n);let d=l.createDiv();d.createDiv({cls:"af-detail-header-name",text:n.name}),d.createDiv({cls:"af-detail-header-desc",text:n.description??"No description"});let u=o.createDiv({cls:"af-detail-header-actions"}),h=u.createEl("button",{cls:"af-btn-sm primary"});if(T(h,"message-circle","af-btn-icon"),h.appendText(" Chat"),h.onclick=()=>e.openChatSlideover(n),n.enabled){let y=u.createEl("button",{cls:"af-btn-sm"});T(y,"play","af-btn-icon"),y.appendText(" Run Now"),y.onclick=()=>void e.plugin.runAgentPrompt(n.name);let v=u.createEl("button",{cls:"af-btn-sm"});T(v,"pause","af-btn-icon"),v.appendText(" Disable"),v.onclick=()=>void e.plugin.toggleAgent(n.name,!1)}else{let y=u.createEl("button",{cls:"af-btn-sm"});T(y,"play","af-btn-icon"),y.appendText(" Enable"),y.onclick=()=>void e.plugin.toggleAgent(n.name,!0)}let p=u.createEl("button",{cls:"af-btn-sm"});T(p,"edit","af-btn-icon"),p.appendText(" Edit"),p.onclick=()=>e.navigate("edit-agent",n.name);let m=u.createEl("button",{cls:"af-btn-sm danger"});T(m,"trash-2","af-btn-icon"),m.appendText(" Delete"),m.onclick=()=>void e.plugin.deleteAgent(n.name);let f=s.createDiv({cls:"af-detail-tabs"}),g=[{id:"overview",label:"Overview",icon:"layout-dashboard"},{id:"config",label:"Config",icon:"settings"},{id:"runs",label:"Runs",icon:"scroll-text"},{id:"memory",label:"Memory",icon:"file-text"}];for(let y of g){let v=f.createEl("button",{cls:`af-detail-tab${e.getDetailTab()===y.id?" active":""}`});T(v,y.icon,"af-tab-icon"),v.appendText(` ${y.label}`),v.onclick=()=>{e.setDetailTab(y.id),e.rerender()}}let w=s.createDiv({cls:"af-detail-tab-content"});switch(e.getDetailTab()){case"overview":tp(w,e,n,i);break;case"config":sp(w,e,n);break;case"runs":np(w,e,i);break;case"memory":hc(w,e,n);break}}function tp(a,e,t,s){let n=a.createDiv({cls:"af-dash-grid"}),r=s.length,i=s.filter(v=>v.status==="success").length,o=r>0?Math.round(i/r*100):0,l=r>0?Math.round(s.reduce((v,k)=>v+k.durationSeconds,0)/r):0,c=e.plugin.runtime.getUsageRecords().filter(v=>v.agent===t.name),{tokens:d,cost:u}=e.combinedTotals(s,c),h=u>0?` \xB7 $${u.toFixed(2)}`:"";if(e.renderStatCard(n,"Total Runs",String(r),"","activity","all time"),e.renderStatCard(n,"Success Rate",`${o}%`,"","check-circle-2",`${i}/${r}`),e.renderStatCard(n,"Avg Time",`${l}s`,"","clock","per run"),e.renderStatCard(n,"Total Tokens",e.formatTokenCount(d),"","zap",`all time${h}`),t.isFolder&&(t.heartbeatBody.trim()||t.heartbeatEnabled)){let v=a.createDiv({cls:"af-section-card"}),k=v.createDiv({cls:"af-section-header"}),b=k.createDiv({cls:"af-section-title"});T(b,"heart-pulse"),b.appendText(" Heartbeat");let A=k.createDiv({cls:"af-detail-header-actions"}).createDiv({cls:`af-agent-card-toggle${t.heartbeatEnabled?" on":""}`});A.onclick=async()=>{let x=A.hasClass("on");await e.plugin.repository.updateHeartbeat(t.name,{enabled:!x}),await e.plugin.refreshFromVault(),new cn.Notice(`Heartbeat ${x?"paused":"enabled"} for ${t.name}`)};let M=v.createDiv({cls:"af-config-form"});e.renderConfigRow(M,"Schedule",e.cronToHuman(t.heartbeatSchedule));let E=e.plugin.runtime.getNextHeartbeat(t.name);E&&t.heartbeatEnabled&&e.renderConfigRow(M,"Next run",e.timeUntil(E)),t.heartbeatChannel&&e.renderConfigRow(M,"Channel",t.heartbeatChannel)}if(t.skills.length>0){let v=a.createDiv({cls:"af-section-card"}),b=v.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(b,"puzzle"),b.appendText(" Skills");let P=v.createDiv({cls:"af-detail-skills-list"});for(let A of t.skills)P.createSpan({cls:"af-skill-tag",text:A})}let p=t.mcpServers??[];if(p.length>0){let v=a.createDiv({cls:"af-section-card"}),b=v.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(b,"plug"),b.appendText(" MCP Servers");let P=v.createDiv({cls:"af-mcp-overview-list"}),A=e.plugin.repository.getMcpServers();for(let M of p){let E=A.find(O=>O.name===M),x=P.createDiv({cls:"af-mcp-overview-row"}),_=x.createSpan({cls:`af-mcp-status-dot ${E?E.enabled?E.status:"disabled":"disconnected"}`});_.title=E?E.enabled?E.status:"disabled":"unknown",x.createSpan({cls:"af-mcp-overview-name",text:M});let R=E?.toolDetails.length??E?.tools.length??0;R>0?x.createSpan({cls:"af-mcp-overview-tools",text:`${R} tools`}):E&&!E.enabled?x.createSpan({cls:"af-mcp-overview-tools af-muted",text:"disabled"}):E?.status==="needs-auth"&&x.createSpan({cls:"af-mcp-overview-tools af-muted",text:"needs auth"})}}if(t.permissionRules.allow.length>0||t.permissionRules.deny.length>0||t.permissionMode&&t.permissionMode!=="default"){let v=a.createDiv({cls:"af-section-card"}),b=v.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(b,"shield-check"),b.appendText(" Permissions");let P=v.createDiv({cls:"af-config-form"});e.renderConfigRow(P,"Mode",t.permissionMode||"default"),t.permissionRules.allow.length>0&&e.renderConfigRow(P,"Allowed",t.permissionRules.allow.join(", ")),t.permissionRules.deny.length>0&&e.renderConfigRow(P,"Denied",t.permissionRules.deny.join(", "))}let f=a.createDiv({cls:"af-section-card"}),w=f.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(w,"scroll-text"),w.appendText(" Recent Runs");let y=f.createDiv({cls:"af-timeline"});if(s.length===0)e.renderEmptyState(y,"scroll-text","No runs yet","");else for(let v of s.slice(0,5))e.renderTimelineItem(y,v)}function sp(a,e,t){let s=a.createDiv({cls:"af-config-form"});e.renderConfigRow(s,"Name",t.name),e.renderConfigRow(s,"Description",t.description??""),e.renderConfigRow(s,"Model",t.model),e.renderConfigRow(s,"Timeout",`${t.timeout}s`),e.renderConfigRow(s,"Working Directory",t.cwd??"(vault root)"),e.renderConfigRow(s,"Permission Mode",t.permissionMode||"default"),e.renderConfigRow(s,"Approval Required",t.approvalRequired.join(", ")||"none"),t.permissionRules.allow.length>0&&e.renderConfigRow(s,"Allowed Commands",t.permissionRules.allow.join(", ")),t.permissionRules.deny.length>0&&e.renderConfigRow(s,"Blocked Commands",t.permissionRules.deny.join(", ")),e.renderConfigRow(s,"Memory",t.memory?"Enabled":"Disabled"),e.renderConfigRow(s,"Auto-compact",t.autoCompactThreshold&&t.autoCompactThreshold>0?`at ${t.autoCompactThreshold}% context`:"disabled"),t.wikiReferences&&t.wikiReferences.length>0&&e.renderConfigRow(s,"Wiki access",t.wikiReferences.map(o=>o.agent).join(", ")),e.renderConfigRow(s,"Tags",t.tags.join(", ")||"none");let n=s.createDiv({cls:"af-config-prompt-section"});if(n.createDiv({cls:"af-slideover-section-title",text:"SYSTEM PROMPT"}),n.createDiv({cls:"af-output-block",text:t.body||"(empty)"}),t.heartbeatBody.trim()){let o=s.createDiv({cls:"af-config-prompt-section"});o.createDiv({cls:"af-slideover-section-title",text:"HEARTBEAT INSTRUCTION"}),o.createDiv({cls:"af-output-block",text:t.heartbeatBody})}let i=s.createDiv({cls:"af-slideover-actions"}).createEl("button",{cls:"af-btn-sm primary"});T(i,"edit","af-btn-icon"),i.appendText(" Edit Agent"),i.onclick=()=>e.navigate("edit-agent",t.name)}function np(a,e,t){if(t.length===0){e.renderEmptyState(a,"scroll-text","No runs yet","Run this agent to see history");return}for(let s of t){let n=a.createDiv({cls:"af-run-list-item"}),r=n.createDiv({cls:`af-tl-icon ${e.statusToTimelineClass(s.status)}`});(0,cn.setIcon)(r,e.statusToIconName(s.status));let i=n.createDiv({cls:"af-tl-body"}),o=i.createDiv({cls:"af-tl-title"});o.createSpan({text:s.task}),o.createSpan({cls:`af-status-badge ${e.statusToBadgeClass(s.status)}`,text:e.statusToBadgeText(s.status)});let l=i.createDiv({cls:"af-tl-meta"});l.createSpan({text:`${e.formatStarted(s.started)} \xB7 ${e.formatDuration(s.durationSeconds)}`}),s.tokensUsed&&l.createSpan({text:`${s.tokensUsed.toLocaleString()} tokens`}),i.createDiv({cls:"af-tl-desc",text:At(s.output,120)}),n.onclick=()=>e.openSlideover(s)}}async function hc(a,e,t){if(!t.memory){e.renderEmptyState(a,"file-text","Memory disabled","Enable memory in agent config");return}let s=await e.plugin.repository.readWorkingMemory(t.name),n=a.createDiv({cls:"af-form-help"}),r=s?.tokenEstimate??0,i=t.reflection.enabled?`reflection on (${t.reflection.schedule})`:"reflection off";n.setText(`~${r} / ${t.memoryTokenBudget} tokens \xB7 ${i}`),!s||s.sections.length===0?e.renderEmptyState(a,"file-text","No memories yet","Agent will learn from runs"):a.createDiv({cls:"af-output-block"}).setText(at(s.sections));let o=a.createDiv({cls:"af-slideover-actions"}),l=o.createEl("button",{cls:"af-btn-sm"});T(l,"moon","af-btn-icon"),l.appendText(" Reflect now"),l.onclick=async()=>{l.disabled=!0,l.setText(" Reflecting\u2026");let d=await e.plugin.runtime.runReflectionNow(t.name);new cn.Notice(`Agent Fleet: ${d.message}`),await hc((a.empty(),a),e,t)};let c=o.createEl("button",{cls:"af-btn-sm"});T(c,"external-link","af-btn-icon"),c.appendText(" Open in Editor"),c.onclick=()=>void e.plugin.openPath(e.plugin.repository.getWorkingMemoryPath(t.name))}var pc=require("obsidian");function mc(a,e){let t=a.createDiv({cls:"af-runs-page"}),s=e.plugin.runtime.getRecentRuns(),n=t.createDiv({cls:"af-runs-toolbar"});n.createDiv({cls:"af-page-title",text:"Run History"}),n.createDiv({cls:"af-toolbar-spacer"});let r=t.createDiv({cls:"af-runs-table"});if(s.length===0){e.renderEmptyState(r,"scroll-text","No runs yet","Run an agent to see history here");return}let i=r.createEl("table"),l=i.createEl("thead").createEl("tr");for(let d of["Status","Agent","Task","Started","Duration","Tokens","Model"])l.createEl("th",{text:d});let c=i.createEl("tbody");for(let d of s.slice(0,50))ap(c,e,d)}function ap(a,e,t){let s=a.createEl("tr"),r=s.createEl("td").createSpan({cls:`af-status-badge ${e.statusToBadgeClass(t.status)}`}),i=r.createSpan();(0,pc.setIcon)(i,e.statusToIconName(t.status)),r.appendText(` ${e.statusToBadgeText(t.status)}`);let o=s.createEl("td",{cls:"af-agent-link"});o.setText(t.agent),o.onclick=l=>{l.stopPropagation(),e.navigate("agent-detail",t.agent)},s.createEl("td",{text:t.task}),s.createEl("td",{cls:"af-mono",text:e.formatStarted(t.started)}),s.createEl("td",{cls:"af-mono",text:e.formatDuration(t.durationSeconds)}),s.createEl("td",{cls:"af-mono",text:t.tokensUsed?t.tokensUsed.toLocaleString():"\u2014"}),s.createEl("td",{cls:"af-mono",text:t.model}),s.setCssStyles({cursor:"pointer"}),s.onclick=()=>e.openSlideover(t)}var fc=require("obsidian");function gc(a,e){let t=a.createDiv({cls:"af-skills-page"}),s=e.plugin.runtime.getSnapshot(),n=t.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"Skills Library"}),n.createDiv({cls:"af-toolbar-spacer"});let r=n.createEl("button",{cls:"af-btn-sm primary"});T(r,"plus","af-btn-icon"),r.appendText(" New Skill"),r.onclick=()=>void e.plugin.createSkillTemplate();let i=t.createDiv({cls:"af-skills-grid"});if(s.skills.length===0){e.renderEmptyState(i,"puzzle","No skills yet","Create skills to give agents specialized abilities",{label:"New Skill",onClick:()=>void e.plugin.createSkillTemplate()});return}for(let o of s.skills)rp(i,e,o,s.agents)}function rp(a,e,t,s){let n=a.createDiv({cls:"af-skill-card"}),r=n.createDiv({cls:"af-skill-card-header"}),i=r.createDiv({cls:"af-skill-card-icon"});(0,fc.setIcon)(i,ip(t.name));let o=r.createEl("button",{cls:"af-btn-sm af-btn-xs"});T(o,"edit","af-btn-icon"),o.onclick=c=>{c.stopPropagation(),e.navigate("edit-skill",t.name)},n.createDiv({cls:"af-skill-card-name",text:t.name}),n.createDiv({cls:"af-skill-card-desc",text:t.description??"No description"});let l=s.filter(c=>c.skills.includes(t.name));if(l.length>0){let c=n.createDiv({cls:"af-skill-card-agents"});for(let d of l)c.createSpan({cls:"af-skill-card-agent-tag",text:d.name})}}function ip(a){return a.includes("git")?"settings":a.includes("summarize")||a.includes("log")?"activity":a.includes("review")||a.includes("check")?"check-circle-2":a.includes("vault")||a.includes("note")?"file-text":"puzzle"}var Pa=require("obsidian");function vc(a,e){let t=a.createDiv({cls:"af-approvals-page"}),s=e.plugin.runtime.getRecentRuns(),n=t.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"Approvals"}),n.createDiv({cls:"af-toolbar-spacer"});let r=s.filter(o=>(o.approvals??[]).some(l=>l.status==="pending"));if(r.length>0){let o=t.createDiv({cls:"af-section-card"}),c=o.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(c,"alert-triangle"),c.appendText(` Pending (${r.length})`);let d=o.createDiv({cls:"af-approvals-list"});for(let u of r)yc(d,e,u,!0)}else{let o=t.createDiv({cls:"af-section-card"});e.renderEmptyState(o,"shield-check","No pending approvals","All clear!")}let i=s.filter(o=>(o.approvals??[]).some(l=>l.status!=="pending"));if(i.length>0){let o=t.createDiv({cls:"af-section-card"}),c=o.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(c,"check-circle-2"),c.appendText(" History");let d=o.createDiv({cls:"af-approvals-list"});for(let u of i.slice(0,20))yc(d,e,u,!1)}}function yc(a,e,t,s){for(let n of t.approvals??[]){if(s&&n.status!=="pending"||!s&&n.status==="pending")continue;let r=a.createDiv({cls:"af-approval-item"}),i=r.createDiv({cls:"af-approval-item-icon"});n.status==="pending"?((0,Pa.setIcon)(i,"shield-check"),i.addClass("pending")):n.status==="approved"?((0,Pa.setIcon)(i,"check-circle-2"),i.addClass("approved")):((0,Pa.setIcon)(i,"x-circle"),i.addClass("rejected"));let o=r.createDiv({cls:"af-approval-item-body"});if(o.createDiv({cls:"af-approval-item-title",text:`${t.agent} \u2192 ${n.tool}`}),o.createDiv({cls:"af-approval-item-meta",text:`Task: ${t.task} \xB7 ${n.command??"no command"} \xB7 ${e.formatStarted(t.started)}`}),n.reason&&o.createDiv({cls:"af-approval-item-reason",text:`Reason: ${n.reason}`}),s&&n.status==="pending"){let l=r.createDiv({cls:"af-approval-item-actions"}),c=l.createEl("button",{cls:"af-btn-approve"});T(c,"check-circle-2","af-btn-icon"),c.appendText(" Approve"),c.onclick=()=>void e.plugin.runtime.resolveApproval(t,n.tool,"approved").then(()=>e.rerender());let d=l.createEl("button",{cls:"af-btn-reject"});T(d,"x-circle","af-btn-icon"),d.appendText(" Reject"),d.onclick=()=>void e.plugin.runtime.resolveApproval(t,n.tool,"rejected").then(()=>e.rerender())}}}var wc=require("obsidian");function bc(a,e){let t=a.createDiv({cls:"af-agents-page"}),s=e.plugin.runtime.getSnapshot(),n=t.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"Channels"}),n.createDiv({cls:"af-toolbar-spacer"});let r=n.createEl("button",{cls:"af-btn-sm primary"});T(r,"plus","af-btn-icon"),r.appendText(" New Channel"),r.onclick=()=>e.navigate("create-channel");let i=t.createDiv({cls:"af-agents-grid"});if(s.channels.length===0){e.renderEmptyState(i,"radio","No channels configured","Connect an agent to Slack or another chat platform",{label:"New Channel",onClick:()=>e.navigate("create-channel")});return}for(let o of s.channels)op(i,e,o,s.validationIssues)}function op(a,e,t,s){let n=e.plugin.channelManager?.getChannelStatus(t.name)??"disabled",r=Ur(n),i=t.enabled&&n!=="disabled"?"af-agent-card":"af-agent-card disabled",o=a.createDiv({cls:i});o.setCssStyles({cursor:"default"});let l=o.createDiv({cls:"af-agent-card-header"}),c=l.createDiv({cls:`af-agent-card-avatar ${r}`});(0,wc.setIcon)(c,"radio");let d=l.createDiv({cls:"af-agent-card-titleblock"});d.createDiv({cls:"af-agent-card-name",text:t.name}),d.createDiv({cls:"af-agent-card-desc",text:`Default: ${t.defaultAgent}`});let u=l.createSpan({cls:`af-pill ${lp(n)}`});if(u.createSpan({cls:"af-dot"}),u.appendText(` ${n}`),t.allowedAgents.length>0){let b=o.createDiv({cls:"af-agent-card-skills"});for(let P of t.allowedAgents){let A=b.createSpan({cls:"af-skill-tag",text:P});P===t.defaultAgent&&A.setCssStyles({fontWeight:"700"})}}let h=o.createDiv({cls:"af-agent-card-stats"}),p=e.plugin.channelManager?.getSessionCount(t.name)??0,m=e.plugin.channelManager?.getMetrics(t.name),f=t.allowedAgents.length>0?String(t.allowedAgents.length):"all";e.renderAgentStat(h,f,"Agents"),e.renderAgentStat(h,String(p),"Sessions"),e.renderAgentStat(h,String(m?.messagesReceived??0),"In"),e.renderAgentStat(h,String(m?.messagesSent??0),"Out");let g=o.createDiv({cls:"af-agent-card-footer"}),w=[t.type];t.enabled||w.push("disabled"),t.allowedUsers.length>0?w.push(`${t.allowedUsers.length} user(s)`):w.push("allowlist empty"),g.createSpan({cls:"af-agent-card-meta",text:w.join(" \xB7 ")});let v=g.createDiv({cls:"af-agent-card-actions"}).createEl("button",{cls:"af-btn-sm"});T(v,"edit","af-btn-icon"),v.appendText(" Edit"),v.onclick=b=>{b.stopPropagation(),e.navigate("edit-channel",t.name)};let k=s.filter(b=>b.path===t.filePath);if(k.length>0){let b=o.createDiv({cls:"af-channel-issues"});for(let P of k)b.createDiv({cls:"af-channel-issue-row",text:P.message})}}function lp(a){switch(a){case"connected":return"green";case"connecting":case"reconnecting":return"blue";case"needs-auth":case"error":return"red";case"stopped":case"disabled":default:return""}}var dn=require("obsidian");function kc(a){let e=/^##\s+Lint\s+(\d{4}-\d{2}-\d{2})\s*$/gm,t,s=-1,n="";for(;(t=e.exec(a))!==null;)t.index>s&&(s=t.index,n=t[1]??"");if(s<0)return null;let r=a.slice(s),i=r.search(/\n##\s+(?!\s*#)/),o=i<0?r:r.slice(0,i);return{date:n,summary:Ea(o,"Summary"),autoApplied:Ea(o,"Auto-applied"),needsReview:Ea(o,"Needs review"),refreshChained:Ea(o,"Refresh chained")}}function Ea(a,e){let t=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`^###\\s+${t}\\s*$`,"m").exec(a);if(!n)return[];let r=n.index+n[0].length,i=a.slice(r),o=i.search(/\n###\s+/),c=(o<0?i:i.slice(0,o)).split(/\r?\n/).map(u=>u.trimEnd()),d=[];for(let u of c){let h=u.replace(/^\s+/,"");h.startsWith("- ")?d.push(h.slice(2).trim()):d.length>0&&(u.startsWith(" ")||u.startsWith(" "))&&(d[d.length-1]+=" "+h)}return d}async function xc(a,e){let t=a.createDiv({cls:"af-agents-page"}),s=e.plugin.runtime.getSnapshot(),n=t.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"Wiki Keepers"}),n.createDiv({cls:"af-toolbar-spacer"});let r=s.agents.filter(o=>o.wikiKeeper!==void 0);if(r.length===0){e.renderEmptyState(t,"library","No Wiki Keepers yet","Open Settings \u2192 Agent Fleet \u2192 Wiki Keepers \u2192 + Add to create one.");return}let i=t.createDiv({cls:"af-wk-list"});i.setCssStyles({display:"flex"}),i.setCssStyles({flexDirection:"column"}),i.setCssStyles({gap:"16px"});for(let o of r)await cp(i,e,o)}async function cp(a,e,t){let s=t.wikiKeeper,n=a.createDiv({cls:"af-card"});n.setCssStyles({padding:"16px"}),n.setCssStyles({border:"1px solid var(--background-modifier-border)"}),n.setCssStyles({borderRadius:"8px"});let r=n.createDiv();r.setCssStyles({display:"flex"}),r.setCssStyles({alignItems:"center"}),r.setCssStyles({gap:"12px"}),r.setCssStyles({marginBottom:"12px"});let i=r.createDiv();i.setCssStyles({flex:"1"}),i.createEl("strong",{text:t.name});let o=s.scopeRoot||"(whole vault)";i.createEl("div",{text:`Scope: ${o} \xB7 topics: ${s.topicsRoot}/ \xB7 log: ${s.logPath}`,cls:"af-form-hint"});let l=r.createEl("button",{cls:"af-btn-sm"});l.appendText("Open log"),l.onclick=()=>{let f=s.scopeRoot?`${s.scopeRoot}/${s.logPath}`:s.logPath,g=e.plugin.app.vault.getAbstractFileByPath(f);g instanceof dn.TFile?e.plugin.app.workspace.getLeaf().openFile(g):new dn.Notice(`Log file not found: ${f}`)};let c=s.scopeRoot?`${s.scopeRoot}/${s.logPath}`:s.logPath,d=e.plugin.app.vault.getAbstractFileByPath(c),u=null;if(d instanceof dn.TFile)try{let f=await e.plugin.app.vault.cachedRead(d);u=kc(f)}catch{u=null}if(!u){n.createDiv({cls:"af-form-hint"}).setText("No lint report yet. Run wiki-lint manually or wait for the weekly task to fire.");return}let h=n.createDiv();if(h.setCssStyles({display:"flex"}),h.setCssStyles({alignItems:"baseline"}),h.setCssStyles({gap:"12px"}),h.setCssStyles({marginBottom:"8px"}),h.createEl("strong",{text:`Lint ${u.date}`}),h.createSpan({cls:"af-form-hint",text:`${u.summary.length} summary lines \xB7 ${u.autoApplied.length} auto-applied \xB7 ${u.needsReview.length} needs review`}),u.summary.length>0){let f=n.createEl("details");f.createEl("summary",{text:"Summary"});let g=f.createEl("ul");g.setCssStyles({marginTop:"4px"});for(let w of u.summary)g.createEl("li",{text:w})}if(u.autoApplied.length>0){let f=n.createEl("details");f.createEl("summary",{text:`Auto-applied (${u.autoApplied.length})`});let g=f.createEl("ul");g.setCssStyles({marginTop:"4px"});for(let w of u.autoApplied)g.createEl("li",{text:w})}if(u.refreshChained.length>0){let f=n.createEl("details");f.createEl("summary",{text:`Refresh chained (${u.refreshChained.length})`});let g=f.createEl("ul");g.setCssStyles({marginTop:"4px"});for(let w of u.refreshChained)g.createEl("li",{text:w})}let p=n.createDiv();if(p.setCssStyles({marginTop:"12px"}),p.createEl("strong",{text:`Needs review (${u.needsReview.length})`}),u.needsReview.length===0){p.createDiv({cls:"af-form-hint",text:"All clear. Nothing requires manual review from this lint pass."});return}let m=p.createDiv();m.setCssStyles({display:"flex"}),m.setCssStyles({flexDirection:"column"}),m.setCssStyles({gap:"6px"}),m.setCssStyles({marginTop:"8px"});for(let f of u.needsReview){let g=m.createDiv();g.setCssStyles({display:"flex"}),g.setCssStyles({alignItems:"flex-start"}),g.setCssStyles({gap:"8px"}),g.setCssStyles({padding:"8px 10px"}),g.setCssStyles({background:"var(--background-secondary)"}),g.setCssStyles({borderRadius:"4px"}),g.setCssStyles({fontSize:"13px"});let w=g.createDiv();w.setCssStyles({flex:"1"}),w.setText(f);let y=g.createEl("button",{cls:"af-btn-sm",text:"Dismiss"});y.title="Hide this item from the dashboard until the next lint pass (does not modify log.md).",y.onclick=()=>{g.remove()}}}var Sc=require("obsidian");function Cc(a,e,t){let s=a.createDiv({cls:"af-task-detail-page"});if(!t){e.renderEmptyState(s,"circle-dot","No task selected","");return}let n=e.plugin.runtime.getSnapshot().tasks.find(_=>_.taskId===t);if(!n){e.renderEmptyState(s,"circle-dot","Task not found",`Task "${t}" was not found`);return}let r=e.plugin.runtime.getSnapshot(),i=e.plugin.runtime.getRecentRuns().filter(_=>_.task===t),o=r.agents.find(_=>_.name===n.agent),l=s.createDiv({cls:"af-detail-header"}),c=l.createDiv({cls:"af-detail-header-left"}),d=c.createDiv({cls:"af-agent-card-avatar idle"});(0,Sc.setIcon)(d,"circle-dot");let u=c.createDiv();u.createDiv({cls:"af-detail-header-name",text:n.taskId}),u.createDiv({cls:"af-detail-header-desc",text:`Agent: ${n.agent}`});let h=l.createDiv({cls:"af-detail-header-actions"}),p=h.createEl("button",{cls:"af-btn-sm"});T(p,"edit","af-btn-icon"),p.appendText(" Edit"),p.onclick=()=>e.navigate("edit-task",n.taskId);let m=h.createEl("button",{cls:"af-btn-sm primary"});T(m,"play","af-btn-icon"),m.appendText(" Run Now"),m.onclick=()=>void e.plugin.runtime.runTaskNow(n);let f=s.createDiv({cls:"af-section-card"}),w=f.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(w,"file-text"),w.appendText(" Details");let y=f.createDiv({cls:"af-config-form"});e.renderConfigRow(y,"Agent",n.agent),e.renderConfigRow(y,"Priority",n.priority.charAt(0).toUpperCase()+n.priority.slice(1)),e.renderConfigRow(y,"Status",n.enabled?"Enabled":"Disabled");let v=n.schedule?e.humanizeCron(n.schedule):n.runAt??"Manual (run on demand)";e.renderConfigRow(y,"Schedule",v),n.schedule&&e.renderConfigRow(y,"Catch up if missed",n.catchUp?"Yes":"No"),e.renderConfigRow(y,"Created",n.created),e.renderConfigRow(y,"Runs",String(n.runCount)),n.lastRun&&e.renderConfigRow(y,"Last Run",e.formatStarted(n.lastRun));let k=s.createDiv({cls:"af-section-card"}),P=k.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(P,"message-square"),P.appendText(" Instructions"),k.createDiv({cls:"af-output-block",text:n.body||"(empty)"});let A=s.createDiv({cls:"af-section-card"}),E=A.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(E,"scroll-text"),E.appendText(" Recent Runs");let x=A.createDiv({cls:"af-timeline"});if(i.length===0)e.renderEmptyState(x,"scroll-text","No runs yet","");else for(let _ of i.slice(0,10))e.renderTimelineItem(x,_)}var we=require("obsidian");function Tc(a,e){let t=a.createDiv({cls:"af-agents-page"}),s=t.createDiv({cls:"af-agents-toolbar"});s.createDiv({cls:"af-page-title",text:"MCP Servers"}),s.createDiv({cls:"af-toolbar-spacer"});let n=s.createEl("button",{cls:"af-btn-sm primary"});T(n,"plus","af-btn-icon"),n.appendText(" Add Server"),n.onclick=()=>e.navigate("add-mcp-server");let r=e.plugin.repository.getMcpServers();if(r.length===0){e.renderEmptyState(t,"plug","No MCP servers registered","Click 'Add Server' above to register one.");return}let i=t.createDiv({cls:"af-agents-grid"});for(let o of r)up(i,e,o)}function Wr(a,e){return a.plugin.mcpAuth.hasToken(e.name)}function dp(a,e){return e.type!=="stdio"&&(e.auth==="oauth"||e.auth==="bearer")&&!Wr(a,e)}function up(a,e,t){let s=a.createDiv({cls:`af-mcp-card${t.enabled?"":" af-mcp-card-disabled"}`}),n=dp(e,t),r=s.createDiv({cls:"af-agent-card-header"}),i=t.enabled?n?"pending":"idle":"disabled",o=r.createDiv({cls:`af-agent-card-avatar ${i}`});(0,we.setIcon)(o,"plug");let l=r.createDiv({cls:"af-agent-card-titleblock"});l.createDiv({cls:"af-agent-card-name",text:t.name});let c=l.createDiv({cls:"af-agent-card-desc af-mcp-meta"});c.createSpan({cls:"af-mcp-type-badge",text:t.type}),t.source==="imported"&&c.createSpan({cls:"af-badge",text:"imported"});let d=r.createDiv({cls:`af-agent-card-toggle${t.enabled?" on":""}`});d.onclick=f=>{f.stopPropagation(),e.plugin.repository.setMcpServerEnabled(t.name,!t.enabled).then(async()=>{await e.plugin.refreshFromVault(),e.rerender()})};let u=s.createDiv({cls:`af-mcp-status-badge ${t.enabled?n?"needs-auth":"connected":"disabled"}`}),h=u.createSpan();if(t.enabled?n?((0,we.setIcon)(h,"alert-circle"),u.createSpan({text:" Needs auth"})):((0,we.setIcon)(h,"check-circle"),u.createSpan({text:t.type==="stdio"?" Enabled":" Authenticated"})):((0,we.setIcon)(h,"pause"),u.createSpan({text:" Disabled"})),t.description){let f=Ac(t.description,120);s.createDiv({cls:"af-mcp-description",text:f})}let p=t.url??t.command??"";p&&s.createDiv({cls:"af-mcp-command",text:At(p,60)});let m=e.mcpProbeCache.get(t.name);if(m&&m.length>0){let f=s.createDiv({cls:"af-mcp-tool-footer"}),g=f.createDiv({cls:"af-mcp-tool-count"}),w=g.createSpan();(0,we.setIcon)(w,"wrench"),g.createSpan({text:` ${m.length} tools`});let y=f.createDiv({cls:"af-mcp-tool-chips"});for(let v of m.slice(0,4))y.createSpan({cls:"af-mcp-tool-chip",text:v.name});m.length>4&&y.createSpan({cls:"af-mcp-tool-chip af-mcp-tool-chip-more",text:`+${m.length-4}`})}if(e.authenticatingServers.has(t.name)){let g=s.createDiv({cls:"af-mcp-auth-row"}).createEl("button",{cls:"af-btn-sm primary",attr:{disabled:"true"}}),w=g.createSpan({cls:"af-spin"});(0,we.setIcon)(w,"loader-2"),g.appendText(" Authenticating\u2026")}else if(t.enabled&&n&&t.auth==="oauth"){let g=s.createDiv({cls:"af-mcp-auth-row"}).createEl("button",{cls:"af-btn-sm primary"}),w=g.createSpan();(0,we.setIcon)(w,"key"),g.appendText(" Authenticate"),g.onclick=y=>{y.stopPropagation(),_c(e,t)}}s.onclick=()=>Pc(e,t)}async function _c(a,e){if(!e.url){new we.Notice("No URL found for this server \u2014 can't authenticate.");return}a.authenticatingServers.add(e.name),a.rerender(),new we.Notice(`Authenticating ${e.name}\u2026 Complete authorization in your browser.`,1e4);try{let t=e.type==="sse"?"sse":"http";await a.plugin.mcpManager.authenticateServer(e.name,e.url,t),new we.Notice(`${e.name} authenticated successfully!`)}catch(t){let s=t instanceof Error?t.message:String(t);new we.Notice(`Authentication failed: ${s}`,8e3)}finally{a.authenticatingServers.delete(e.name),a.rerender()}}async function hp(a,e){try{let t=await a.plugin.mcpManager.probeServer(e);a.mcpProbeCache.set(e.name,t),t.length===0&&new we.Notice(`No tools discovered for ${e.name}.`)}catch(t){let s=t instanceof Error?t.message:String(t);new we.Notice(`Probe failed: ${At(s,150)}`)}}function Ac(a,e){let t=re(a)[0]??a,s=t.split(/(?<=[.!?])\s/)[0]??t,n=s.length<t.length?s:t;return n.length<=e?n:n.slice(0,e-1)+"\u2026"}function Pc(a,e){a.contentEl.querySelector(".af-slideover-overlay")?.remove();let t=a.contentEl.createDiv({cls:"af-slideover-overlay"}),s=t.createDiv({cls:"af-slideover"}),n=s.createDiv({cls:"af-slideover-header"});n.createDiv({cls:"af-slideover-title",text:e.name});let r=n.createEl("button",{cls:"clickable-icon"});(0,we.setIcon)(r,"cross"),r.onclick=()=>t.remove(),t.onclick=g=>{g.target===t&&t.remove()};let i=s.createDiv({cls:"af-slideover-body"});if(e.description){let g=i.createDiv({cls:"af-slideover-section"});g.createDiv({cls:"af-slideover-section-title",text:"DESCRIPTION"}),g.createDiv({cls:"af-mcp-detail-description",text:e.description})}let o=i.createDiv({cls:"af-slideover-section"});o.createDiv({cls:"af-slideover-section-title",text:"SERVER INFO"}),a.renderDetailRow(o,"Name",e.name),a.renderDetailRow(o,"Transport",e.type),a.renderDetailRow(o,"Enabled",e.enabled?"yes":"no"),e.type!=="stdio"&&(a.renderDetailRow(o,"Auth",e.auth??"none"),a.renderDetailRow(o,"Authenticated",Wr(a,e)?"yes":"no")),e.source&&a.renderDetailRow(o,"Source",e.source),e.url&&a.renderDetailRow(o,"URL",e.url),e.command&&a.renderDetailRow(o,"Command",e.command),e.args&&e.args.length>0&&a.renderDetailRow(o,"Args",e.args.join(" "));let l=a.mcpProbeCache.get(e.name)??[],c=i.createDiv({cls:"af-slideover-section"});c.createDiv({cls:"af-slideover-section-title"}).setText(`TOOLS (${l.length})`);let u=c.createEl("button",{cls:"af-btn-sm"}),h=u.createSpan();if((0,we.setIcon)(h,"wrench"),u.appendText(" Probe tools"),u.onclick=async()=>{u.disabled=!0,u.setText(" Probing\u2026"),await hp(a,e),t.remove(),Pc(a,e)},l.length>0)for(let g of l){let w=c.createDiv({cls:"af-mcp-tool-detail"}),y=w.createDiv({cls:"af-mcp-tool-detail-header"}),v=y.createSpan({cls:"af-mcp-tool-detail-name"}),k=v.createSpan();if((0,we.setIcon)(k,"wrench"),v.createSpan({text:` ${g.name}`}),g.inputSchema){let b=g.inputSchema.required??[];b.length>0&&y.createSpan({cls:"af-mcp-tool-param-count",text:`${b.length} param${b.length!==1?"s":""}`})}if(g.description){let b=re(g.description).filter(M=>M.trim()),P=b.slice(0,2).join(" ").trim();if(b.length>2){let M=w.createEl("details",{cls:"af-mcp-tool-detail-desc"});M.createEl("summary",{text:Ac(P,200)}),M.createDiv({cls:"af-mcp-tool-detail-full",text:g.description})}else w.createDiv({cls:"af-mcp-tool-detail-desc",text:P})}if(g.inputSchema){let b=g.inputSchema.properties,P=new Set(g.inputSchema.required??[]);if(b&&Object.keys(b).length>0){let A=w.createDiv({cls:"af-mcp-tool-params"});for(let[M,E]of Object.entries(b)){let x=A.createDiv({cls:"af-mcp-tool-param"});x.createSpan({cls:"af-mcp-tool-param-name",text:M}),E.type&&x.createSpan({cls:"af-mcp-tool-param-type",text:E.type}),P.has(M)&&x.createSpan({cls:"af-mcp-tool-param-required",text:"required"}),E.description&&x.createSpan({cls:"af-mcp-tool-param-desc",text:At(E.description,80)})}}}}else c.createDiv({cls:"af-form-hint",text:'Click "Probe tools" to discover the tools this server exposes.'});let p=i.createDiv({cls:"af-slideover-section"});if(p.createDiv({cls:"af-slideover-section-title",text:"ACTIONS"}),e.enabled&&e.url&&e.auth==="oauth"&&!Wr(a,e)){let g=p.createEl("button",{cls:"af-btn-sm primary"}),w=g.createSpan();(0,we.setIcon)(w,"key"),g.appendText(" Authenticate"),g.onclick=()=>{t.remove(),_c(a,e)}}let m=p.createEl("button",{cls:"af-btn-sm danger"}),f=m.createSpan();(0,we.setIcon)(f,"trash-2"),m.appendText(" Remove Server"),m.onclick=async()=>{try{await a.plugin.repository.deleteMcpServer(e.name),a.plugin.mcpAuth.removeToken(e.name),a.mcpProbeCache.delete(e.name),new we.Notice(`Server "${e.name}" removed.`),t.remove(),await a.plugin.refreshFromVault(),a.rerender()}catch(g){let w=g instanceof Error?g.message:String(g);new we.Notice(`Failed to remove server: ${w}`)}}}var Ec={dashboard:"Dashboard",agents:"Agents",kanban:"Tasks Board",runs:"Run History",skills:"Skills Library",approvals:"Approvals",mcp:"MCP Servers",channels:"Channels","wiki-keepers":"Wiki Keepers","agent-detail":"Agent Details","task-detail":"Task Details","create-agent":"Create Agent","create-task":"Create Task","create-skill":"Create Skill","edit-agent":"Edit Agent","edit-task":"Edit Task","edit-skill":"Edit Skill","create-channel":"Create Channel","edit-channel":"Edit Channel","add-mcp-server":"Add MCP Server"},pp={dashboard:"layout-dashboard",agents:"bot",kanban:"columns-3",runs:"scroll-text",skills:"puzzle",approvals:"shield-check",mcp:"plug",channels:"radio","wiki-keepers":"library","agent-detail":"bot","task-detail":"circle-dot","create-agent":"plus","create-task":"plus","create-skill":"plus","edit-agent":"edit","edit-task":"edit","edit-skill":"edit","create-channel":"plus","edit-channel":"edit","add-mcp-server":"plus"},mp=["dashboard","agents","kanban","runs","approvals","skills","wiki-keepers","mcp","channels"],Dc="agent-fleet-welcome-dismissed",fp=new Set(Ls.map(a=>/^agents\/([^/]+?)(?:\.md)?(?:\/|$)/.exec(a.path)?.[1]).filter(a=>!!a)),un=class extends Z.ItemView{constructor(t,s){super(t);this.plugin=s}currentPage="dashboard";detailContext;agentDetailTab="overview";streamingUnsubscribes=[];runningCardTickers=[];runningCardInterval;channelStatusUnsubscribe;authenticatingServers=new Set;mcpProbeCache=new Map;getViewType(){return Yt}getDisplayText(){return"Agent Fleet"}getIcon(){return"bot"}async onOpen(){this.plugin.subscribeView(this),this.channelStatusUnsubscribe=this.plugin.channelManager?.onStatusChange(()=>{this.currentPage==="channels"&&this.render()}),await this.render()}async onClose(){this.cleanupStreaming(),this.channelStatusUnsubscribe?.(),this.channelStatusUnsubscribe=void 0,this.plugin.unsubscribeView(this)}navigateTo(t,s){this.currentPage=t,this.detailContext=s,t!=="agent-detail"&&(this.agentDetailTab="overview"),this.render()}async render(){this.cleanupStreaming();let t=this.contentEl;t.empty(),t.addClass("af-root");let n=t.createDiv({cls:"af-app"}).createDiv({cls:"af-main-content"});this.renderTopBar(n),this.renderTabBar(n);let r=n.createDiv({cls:"af-page"});switch(this.currentPage){case"dashboard":this.renderDashboardPage(r);break;case"agents":dc(r,this.agentsPageDeps());break;case"kanban":this.renderKanbanPage(r);break;case"runs":mc(r,this.runsPageDeps());break;case"skills":gc(r,this.skillsPageDeps());break;case"approvals":vc(r,this.approvalsPageDeps());break;case"mcp":Tc(r,this.mcpPageDeps());break;case"channels":bc(r,this.channelsPageDeps());break;case"wiki-keepers":xc(r,this.basePageDeps());break;case"agent-detail":uc(r,this.agentDetailPageDeps(),this.detailContext);break;case"task-detail":Cc(r,this.taskDetailPageDeps(),this.detailContext);break;case"create-agent":this.renderCreateAgentPage(r);break;case"create-task":this.renderCreateTaskPage(r);break;case"create-skill":this.renderCreateSkillPage(r);break;case"edit-agent":this.renderEditAgentPage(r);break;case"edit-task":this.renderEditTaskPage(r);break;case"edit-skill":this.renderEditSkillPage(r);break;case"create-channel":this.renderCreateChannelPage(r);break;case"edit-channel":this.renderEditChannelPage(r);break;case"add-mcp-server":this.renderAddMcpServerPage(r);break}}navigate(t,s){this.navigateTo(t,s)}cleanupStreaming(){for(let t of this.streamingUnsubscribes)t();this.streamingUnsubscribes=[],this.runningCardTickers=[],this.runningCardInterval!==void 0&&(window.clearInterval(this.runningCardInterval),this.runningCardInterval=void 0)}renderTopBar(t){let s=t.createDiv({cls:"af-top-bar"}),n=s.createDiv({cls:"af-top-bar-title"});T(n,"bot","af-top-bar-icon"),n.createSpan({text:"Agent Fleet"});let r=s.createDiv({cls:"af-breadcrumb"}),i=r.createSpan({cls:"af-breadcrumb-sep"});(0,Z.setIcon)(i,"chevron-right");let o=(f,g,w)=>{let y=r.createSpan({cls:g?"af-breadcrumb-link":"",text:f});g&&(y.onclick=()=>this.navigate(g,w))},l=()=>{let f=r.createSpan({cls:"af-breadcrumb-sep"});(0,Z.setIcon)(f,"chevron-right")};switch(this.currentPage){case"agent-detail":o("Agents","agents"),l(),o(this.detailContext??"Agent");break;case"task-detail":o("Tasks Board","kanban"),l(),o(this.detailContext??"Task");break;case"edit-agent":o("Agents","agents"),l(),o(this.detailContext??"Agent","agent-detail",this.detailContext),l(),o("Edit");break;case"edit-task":o("Tasks Board","kanban"),l(),o(this.detailContext??"Task","task-detail",this.detailContext),l(),o("Edit");break;case"create-agent":o("Agents","agents"),l(),o("New Agent");break;case"create-task":o("Tasks Board","kanban"),l(),o("New Task");break;case"create-skill":o("Skills Library","skills"),l(),o("New Skill");break;case"edit-skill":o("Skills Library","skills"),l(),o(this.detailContext??"Skill"),l(),o("Edit");break;case"create-channel":o("Channels","channels"),l(),o("New Channel");break;case"edit-channel":o("Channels","channels"),l(),o(this.detailContext??"Channel"),l(),o("Edit");break;case"add-mcp-server":o("MCP Servers","mcp"),l(),o("Add Server");break;default:o(Ec[this.currentPage])}s.createDiv({cls:"af-top-bar-spacer"});let c=s.createDiv({cls:"af-search-wrap"});T(c,"search","af-search-icon");let d=c.createEl("input",{cls:"af-search-input",attr:{type:"text",placeholder:"Search agents, tasks, runs..."}}),u;d.addEventListener("input",()=>{window.clearTimeout(u),u=window.setTimeout(()=>{this.handleSearch(d.value,c)},200)}),d.addEventListener("blur",()=>{window.setTimeout(()=>c.querySelector(".af-search-results")?.remove(),200)});let h=this.plugin.runtime.getFleetStatus(),p=s.createDiv({cls:"af-status-pills"});if(h.running>0){let f=p.createSpan({cls:"af-pill yellow"});f.createSpan({cls:"af-dot pulse"}),f.appendText(` ${h.running} Running`)}if(h.pending>0){let f=p.createSpan({cls:"af-pill blue"});f.createSpan({cls:"af-dot"}),f.appendText(` ${h.pending} Pending`)}let m=p.createSpan({cls:"af-pill green"});m.createSpan({cls:"af-dot"}),m.appendText(` ${h.completedToday} Today`)}renderTabBar(t){let s=t.createDiv({cls:"af-tab-bar"}),n=this.plugin.runtime.getSnapshot(),r=this.plugin.runtime.getFleetStatus();for(let i of mp){let o=this.currentPage===i||i==="agents"&&(this.currentPage==="agent-detail"||this.currentPage==="edit-agent"||this.currentPage==="create-agent")||i==="kanban"&&(this.currentPage==="task-detail"||this.currentPage==="edit-task")||i==="skills"&&(this.currentPage==="edit-skill"||this.currentPage==="create-skill")||i==="mcp"&&this.currentPage==="add-mcp-server",l=s.createEl("button",{cls:`af-tab-item${o?" active":""}`}),c=l.createSpan({cls:"af-tab-icon"});if((0,Z.setIcon)(c,pp[i]),l.appendText(i==="dashboard"?"Overview":Ec[i]),i==="agents")l.createSpan({cls:"af-badge",text:String(n.agents.length)});else if(i==="skills")l.createSpan({cls:"af-badge",text:String(n.skills.length)});else if(i==="mcp"){let d=this.plugin.repository.getMcpServers().length;l.createSpan({cls:"af-badge",text:String(d)})}else i==="approvals"&&r.pending>0&&l.createSpan({cls:"af-badge af-badge-warn",text:String(r.pending)});l.onclick=()=>this.navigate(i)}}renderDashboardPage(t){let s=t.createDiv({cls:"af-dashboard"}),n=this.plugin.runtime.getSnapshot(),r=this.plugin.runtime.getRecentRuns(),i=this.plugin.runtime.getFleetStatus();this.maybeRenderWelcomeCard(s,n.agents,r);let o=r.filter(b=>(b.approvals??[]).some(P=>P.status==="pending"));for(let b of o)for(let P of b.approvals??[])P.status==="pending"&&this.renderApprovalBanner(s,b,P.tool);let l=s.createDiv({cls:"af-dash-grid"}),c=n.agents.filter(b=>b.enabled).length,d=n.agents.length;this.renderStatCard(l,"Active Agents",`${c}`,`/ ${d}`,"bot",`${c} of ${d} enabled`);let u=this.toLocalDateStr(new Date),h=r.filter(b=>this.runToLocalDate(b.started)===u),p=h.filter(b=>b.status==="success").length,m=h.filter(b=>b.status==="failure"||b.status==="timeout").length;this.renderStatCard(l,"Runs Today",String(h.length),"","activity",`${p} passed \xB7 ${m} failed \xB7 ${i.running} running`);let f=this.plugin.runtime.getUsageRecords().filter(b=>this.runToLocalDate(b.ts)===u),{tokens:g,cost:w}=this.combinedTotals(h,f),y=w>0?` \xB7 $${w.toFixed(2)}`:"";this.renderStatCard(l,"Tokens Used",qr(g),"","zap",`today${y}`);let v=n.tasks.filter(b=>b.enabled&&b.schedule);this.renderStatCard(l,"Scheduled Tasks",String(v.length),"","clock",v.length>0?`Next: ${this.getNextTaskLabel(v)}`:"No scheduled tasks"),this.renderChartsRow(s,r,this.plugin.runtime.getChartRuns()),this.renderStreamingCards(s);let k=s.createDiv({cls:"af-dash-split"});this.renderActivityTimeline(k,r),this.renderFleetStatusPanel(k,n)}maybeRenderWelcomeCard(t,s,n){if(this.plugin.app.loadLocalStorage(Dc)||!(s.length>0&&s.every(p=>fp.has(p.name))&&n.length===0))return;let i=t.createDiv({cls:"af-welcome-card"}),o=i.createDiv({cls:"af-welcome-header"}),l=o.createDiv({cls:"af-section-title"});T(l,"sparkles"),l.appendText(" Welcome to Agent Fleet");let c=o.createEl("button",{cls:"clickable-icon af-welcome-dismiss",attr:{"aria-label":"Dismiss"}});(0,Z.setIcon)(c,"x"),c.onclick=()=>{this.plugin.app.saveLocalStorage(Dc,"1"),i.remove()},i.createDiv({cls:"af-welcome-sub",text:"Three quick steps to get your fleet going:"});let d=i.createDiv({cls:"af-welcome-steps"}),u=(p,m,f,g,w)=>{let y=d.createDiv({cls:"af-welcome-step"});y.createDiv({cls:"af-welcome-step-num",text:String(p)});let v=y.createDiv({cls:"af-welcome-step-body"}),k=v.createDiv({cls:"af-welcome-step-title"});T(k,m,"af-meta-icon"),k.appendText(` ${f}`),v.createDiv({cls:"af-welcome-step-desc",text:g}),y.onclick=w},h=s.find(p=>p.name==="fleet-orchestrator")??s[0];u(1,"message-circle","Try the Fleet Orchestrator in Chat","It knows this plugin inside out \u2014 ask it to build agents, tasks, and skills for you.",()=>void this.plugin.openChatView(h?.name)),u(2,"bot","Create your own agent","Give it a system prompt, a model, and permissions.",()=>this.navigate("create-agent")),u(3,"radio","Connect a channel (optional)","Talk to your agents from Slack, Telegram, or Discord.",()=>this.navigate("channels"))}renderChartsRow(t,s,n){let r=t.createDiv({cls:"af-charts-row"}),i=r.createDiv({cls:"af-section-card af-chart-section"}),l=i.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(l,"activity"),l.appendText(" Run Activity (14d)");let c=i.createDiv({cls:"af-chart-body"}),d=this.buildChartData(n,14);d.some(w=>w.success+w.failure+w.cancelled>0)?Gl(c,d):this.renderEmptyState(c,"activity","No run data","Run agents to see activity");let u=r.createDiv({cls:"af-section-card af-chart-section"}),p=u.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(p,"target"),p.appendText(" Success Rate");let m=u.createDiv({cls:"af-chart-body af-chart-body-center"}),f=s.length,g=s.filter(w=>w.status==="success").length;f>0?Vl(m,g,f):this.renderEmptyState(m,"target","No data","")}toLocalDateStr(t){let s=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${s(t.getMonth()+1)}-${s(t.getDate())}`}runToLocalDate(t){return this.toLocalDateStr(new Date(t))}runCost(t){return t.costUsd??ql(t.model,t.tokensUsed??0)}usageCost(t){return t.costUsd??Wl(t.model,{inputTokens:t.inputTokens,outputTokens:t.outputTokens,cacheReadTokens:t.cacheReadTokens,cacheCreateTokens:t.cacheCreateTokens})}combinedTotals(t,s){let n=t.reduce((i,o)=>i+(o.tokensUsed??0),0)+s.reduce((i,o)=>i+o.totalTokens,0),r=t.reduce((i,o)=>i+this.runCost(o),0)+s.reduce((i,o)=>i+this.usageCost(o),0);return{tokens:n,cost:r}}buildChartData(t,s){let n=[],r=new Date;for(let i=s-1;i>=0;i--){let o=new Date(r);o.setDate(o.getDate()-i);let l=this.toLocalDateStr(o),c=t.filter(d=>this.runToLocalDate(d.started)===l);n.push({date:l,success:c.filter(d=>d.status==="success").length,failure:c.filter(d=>d.status==="failure"||d.status==="timeout").length,cancelled:c.filter(d=>d.status==="cancelled").length})}return n}renderStreamingCards(t){let n=this.plugin.runtime.getSnapshot().agents.filter(l=>this.plugin.runtime.getAgentState(l.name).status==="running");if(n.length===0)return;let r=t.createDiv({cls:"af-streaming-section"}),o=r.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(o,"terminal"),o.appendText(" Active Agents");for(let l of n)this.renderStreamingCard(r,l.name)}renderStreamingCard(t,s){let n=t.createDiv({cls:"af-streaming-card"}),r=this.plugin.runtime.getAgentState(s),i=this.plugin.runtime.getSnapshot(),o=r.currentTaskId?i.tasks.find(m=>m.taskId===r.currentTaskId):void 0,l=o?` \u2192 ${o.taskId}`:r.currentTaskId?.startsWith("reflection-")?" \u2192 Reflection":r.currentTaskId?.startsWith("heartbeat-")||r.status==="running"?" \u2192 Heartbeat":"",c=n.createDiv({cls:"af-streaming-card-header"});c.createSpan({cls:"af-dot pulse",attr:{style:"background: var(--af-yellow)"}}),c.createSpan({cls:"af-streaming-card-agent",text:` ${s}`}),l&&c.createSpan({cls:"af-streaming-card-task",text:l});let d=n.createDiv({cls:"af-streaming-output"}),u=r.currentTaskId?.startsWith("reflection-")?"Consolidating memory\u2026":"Working\u2026",h=m=>{let f=re(m).filter(g=>g.trim().length>0).slice(-4);d.setText(f.length>0?f.join(`
|
|
12019
|
+
`):u)};h(this.plugin.runtime.getRunOutputBuffer(s));let p=this.plugin.runtime.onRunOutput(s,()=>{h(this.plugin.runtime.getRunOutputBuffer(s)),d.scrollTop=d.scrollHeight});this.streamingUnsubscribes.push(p)}renderApprovalBanner(t,s,n){let r=t.createDiv({cls:"af-approval-banner"}),i=r.createDiv({cls:"af-approval-icon"});(0,Z.setIcon)(i,"shield-check");let o=r.createDiv({cls:"af-approval-text"});o.createDiv({cls:"af-approval-title",text:`${s.agent} wants to run: ${n}`}),o.createDiv({cls:"af-approval-desc",text:`Approval required for tool: ${n}`});let l=r.createDiv({cls:"af-approval-actions"}),c=l.createEl("button",{cls:"af-btn-approve",text:"Approve"});c.onclick=()=>void this.plugin.runtime.resolveApproval(s,n,"approved").then(()=>this.render());let d=l.createEl("button",{cls:"af-btn-reject",text:"Reject"});d.onclick=()=>void this.plugin.runtime.resolveApproval(s,n,"rejected").then(()=>this.render())}renderStatCard(t,s,n,r,i,o){let l=t.createDiv({cls:"af-stat-card"}),c=l.createDiv({cls:"af-stat-label"});T(c,i,"af-stat-icon"),c.appendText(` ${s}`);let d=l.createDiv({cls:"af-stat-value"});d.appendText(n),r&&d.createSpan({cls:"af-stat-value-suffix",text:r}),l.createDiv({cls:"af-stat-sub",text:o})}renderActivityTimeline(t,s){let n=t.createDiv({cls:"af-section-card"}),i=n.createDiv({cls:"af-section-header"}).createDiv({cls:"af-section-title"});T(i,"inbox"),i.appendText(" Recent Activity");let o=n.createDiv({cls:"af-timeline"}),l=s.slice(0,8);if(l.length===0){this.renderEmptyState(o,"inbox","No runs yet","Run an agent to see activity here");return}for(let c of l)this.renderTimelineItem(o,c)}renderTimelineItem(t,s){let n=t.createDiv({cls:"af-timeline-item"}),r=this.statusToTimelineClass(s.status),i=n.createDiv({cls:`af-tl-icon ${r}`});(0,Z.setIcon)(i,this.statusToIconName(s.status));let o=n.createDiv({cls:"af-tl-body"}),l=o.createDiv({cls:"af-tl-title"});l.createSpan({cls:"af-agent-tag",text:s.agent}),l.appendText(` ${s.task}`),o.createDiv({cls:"af-tl-desc",text:At(s.output,100)});let c=o.createDiv({cls:"af-tl-meta"}),d=c.createSpan();if(T(d,"clock","af-meta-icon"),d.appendText(` ${this.formatStarted(s.started)} \xB7 ${this.formatDuration(s.durationSeconds)}`),s.tokensUsed){let u=c.createSpan();T(u,"zap","af-meta-icon"),u.appendText(` ${s.tokensUsed.toLocaleString()} tokens`)}n.onclick=()=>this.openSlideover(s)}renderFleetStatusPanel(t,s){let n=t.createDiv({cls:"af-section-card"}),r=n.createDiv({cls:"af-section-header"}),i=r.createDiv({cls:"af-section-title"});T(i,"bot"),i.appendText(" Fleet Status");let l=r.createDiv({cls:"af-section-actions"}).createEl("button",{cls:"af-btn-sm primary"});T(l,"plus","af-btn-icon"),l.appendText(" New Agent"),l.onclick=()=>void this.plugin.createAgentTemplate();let c=n.createDiv({cls:"af-agent-mini-list"});if(s.agents.length===0){this.renderEmptyState(c,"bot","No agents yet","Create your first agent to get started",{label:"New Agent",onClick:()=>void this.plugin.createAgentTemplate()});return}for(let u of s.agents)this.renderAgentMini(c,u,s.tasks);let d=s.agents.filter(u=>u.enabled);if(d.length>0){let u=n.createDiv({cls:"af-quick-run"}),h=u.createDiv({cls:"af-quick-run-label"});T(h,"zap","af-meta-icon"),h.appendText(" Quick Run");let p=u.createDiv({cls:"af-quick-run-row"}),m=p.createEl("select",{cls:"af-select"});for(let g of d)m.createEl("option",{text:g.name,attr:{value:g.name}});let f=p.createEl("button",{cls:"af-btn-sm primary"});T(f,"play","af-btn-icon"),f.appendText(" Run"),f.onclick=()=>void this.plugin.runAgentPrompt(m.value)}}renderAgentMini(t,s,n){let r=this.plugin.runtime.getAgentState(s.name),i=n.filter(h=>h.agent===s.name),o=this.healthToClass(r.status),l=t.createDiv({cls:"af-agent-mini"}),c=l.createDiv({cls:`af-agent-avatar ${o}`});s.avatar?.trim()?this.renderAgentAvatar(c,s):c.setText(this.getInitials(s.name));let d=l.createDiv({cls:"af-agent-info"});d.createDiv({cls:"af-agent-name",text:s.name});let u="";if(r.status==="running")u=`Running now \xB7 ${i.length} task${i.length!==1?"s":""}`;else if(!s.enabled)u=`Disabled \xB7 ${i.length} task${i.length!==1?"s":""} paused`;else{let h=i.map(p=>p.nextRun).filter(Boolean).sort()[0];u=h?`Next: ${this.formatNextRun(h)} \xB7 ${i.length} task${i.length!==1?"s":""}`:`${i.length} task${i.length!==1?"s":""}`}d.createDiv({cls:"af-agent-desc",text:u}),l.createDiv({cls:`af-agent-status-dot ${o}`}),l.onclick=()=>this.navigate("agent-detail",s.name)}renderAgentStat(t,s,n){let r=t.createDiv({cls:"af-agent-stat"});r.createSpan({cls:"af-agent-stat-value",text:s}),r.createSpan({cls:"af-agent-stat-label",text:n})}renderConfigRow(t,s,n){let r=t.createDiv({cls:"af-detail-row"});r.createSpan({cls:"af-detail-label",text:s}),r.createSpan({cls:"af-detail-value af-mono",text:n})}timeAgo(t){let s=Math.round((Date.now()-t.getTime())/1e3);if(s<60)return"just now";let n=Math.round(s/60);if(n<60)return`${n}m ago`;let r=Math.round(n/60);return r<24?`${r}h ago`:`${Math.round(r/24)}d ago`}timeUntil(t){let s=Math.round((t.getTime()-Date.now())/1e3);if(s<60)return"< 1m";let n=Math.round(s/60);if(n<60)return`in ${n}m`;let r=Math.round(n/60);return r<24?`in ${r}h`:`in ${Math.round(r/24)}d`}renderKanbanPage(t){let s=t.createDiv({cls:"af-kanban-page"}),n=this.plugin.runtime.getSnapshot(),r=this.plugin.runtime.getRecentRuns(),i=s.createDiv({cls:"af-kanban-toolbar"});i.createDiv({cls:"af-page-title",text:"Tasks Board"}),i.createDiv({cls:"af-toolbar-spacer"});let o=i.createEl("button",{cls:"af-btn-sm primary"});T(o,"plus","af-btn-icon"),o.appendText(" New Task"),o.onclick=()=>this.navigate("create-task");let l=s.createDiv({cls:"af-kanban-board"}),c=[],d=[],u=[],h=[],p=[],m=new Set;for(let y of n.agents){let v=this.plugin.runtime.getAgentState(y.name);v.status==="running"&&v.currentTaskId&&m.add(v.currentTaskId)}let f=this.toLocalDateStr(new Date);for(let y of r)y.status==="success"&&this.runToLocalDate(y.started)===f?h.push(y):(y.status==="failure"||y.status==="timeout"||y.status==="cancelled")&&this.runToLocalDate(y.started)===f&&p.push(y);let g=new Set(h.map(y=>y.task)),w=new Set(p.map(y=>y.task));for(let y of n.tasks){let v=g.has(y.taskId)||w.has(y.taskId)||y.lastRun&&this.runToLocalDate(y.lastRun)===f;if(m.has(y.taskId))u.push(y);else{if(v&&!y.schedule)continue;y.schedule&&y.enabled?d.push(y):c.push(y)}}this.renderKanbanColumn(l,"Backlog","inbox",c.length,y=>{for(let v of c)this.renderKanbanTaskCard(y,v,n,!0)},"backlog"),this.renderKanbanColumn(l,"Scheduled","clock",d.length,y=>{for(let v of d)this.renderKanbanTaskCard(y,v,n,!0)},"scheduled"),this.renderKanbanColumn(l,"Running","loader-2",u.length,y=>{for(let v of u)this.renderKanbanRunningCard(y,v)},"running",!1,"running"),this.renderKanbanColumn(l,"Done","check-circle-2",h.length,y=>{for(let v of h.slice(0,10))this.renderKanbanCompletedCard(y,v)},"completed"),this.renderKanbanColumn(l,"Failed","x-circle",p.length,y=>{for(let v of p)this.renderKanbanFailedCard(y,v)},"failed",!1,"failed")}renderKanbanColumn(t,s,n,r,i,o,l=!1,c){let d=t.createDiv({cls:`af-kanban-column${c?` af-kanban-${c}`:""}`});(o==="backlog"||o==="scheduled")&&Kl(d,m=>this.handleTaskDrop(m,o));let h=d.createDiv({cls:"af-kanban-col-header"}).createDiv({cls:"af-kanban-col-title"});T(h,n),h.appendText(` ${s} `),h.createSpan({cls:"af-kanban-col-count",text:String(r)});let p=d.createDiv({cls:"af-kanban-col-body"});if(i(p),r===0&&p.createDiv({cls:"af-kanban-empty",text:"No items"}),l){let f=d.createDiv({cls:"af-kanban-col-add"}).createEl("button");T(f,"plus","af-btn-icon"),f.appendText(" Add task"),f.onclick=()=>{this.navigate("create-task")}}}handleTaskDrop(t,s){let n=this.plugin.runtime.getSnapshot().tasks.find(r=>r.taskId===t);if(n){if(s==="backlog")this.setTaskEnabled(n,!1).then(()=>{new Z.Notice(`Task "${t}" moved to backlog (disabled)`)});else if(s==="scheduled"){if(!n.schedule&&!n.runAt){new Z.Notice(`Task "${t}" needs a schedule. Open task details to set one.`),this.navigate("task-detail",t);return}this.setTaskEnabled(n,!0).then(()=>{new Z.Notice(`Task "${t}" moved to scheduled (enabled)`)})}}}async setTaskEnabled(t,s){let n=this.plugin.app.vault.getAbstractFileByPath(t.filePath);if(!n||!(n instanceof Z.TFile))return;let r=await this.plugin.app.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);i.enabled=s,await this.plugin.app.vault.modify(n,U(i,o)),await this.plugin.refreshFromVault()}renderKanbanTaskCard(t,s,n,r){let i=t.createDiv({cls:`af-kanban-card af-priority-${s.priority}`});if(r){Yl(i,s.taskId);let f=i.createDiv({cls:"af-kanban-card-grip"});(0,Z.setIcon)(f,"grip-vertical")}let o=i.createDiv({cls:"af-kanban-card-header"});o.createDiv({cls:"af-kanban-card-title",text:s.taskId});let c=(n.agents.find(f=>f.name===s.agent)?.enabled??!1)&&s.enabled,d=o.createSpan({cls:`af-kanban-card-status ${c?"active":"inactive"}`});d.title=c?"Active":"Inactive";let u=i.createDiv({cls:"af-kanban-card-agent"}),h=u.createSpan({cls:"af-kanban-card-agent-icon"});(0,Z.setIcon)(h,"bot"),u.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let m=i.createDiv({cls:"af-kanban-card-footer"}).createSpan({cls:"af-kanban-card-schedule"});c?s.schedule?(T(m,"refresh-cw","af-meta-icon"),m.appendText(` ${this.humanizeCron(s.schedule)}`)):m.appendText(s.runAt??"Manual"):(T(m,"pause","af-meta-icon"),m.appendText(" Paused")),i.onclick=()=>this.navigate("task-detail",s.taskId)}renderKanbanRunningCard(t,s){let n=t.createDiv({cls:"af-kanban-card af-kanban-card-running"});n.createDiv({cls:"af-kanban-card-title",text:s.taskId});let r=n.createDiv({cls:"af-kanban-card-agent"}),i=r.createSpan({cls:"af-kanban-card-agent-icon"});(0,Z.setIcon)(i,"bot"),r.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let l=this.plugin.runtime.getSnapshot().agents.find(b=>b.name===s.agent)?.timeout??300,c=this.plugin.runtime.getAgentState(s.agent),d=c.runStarted?new Date(c.runStarted).getTime():Date.now(),p=n.createDiv({cls:"af-kanban-progress"}).createDiv({cls:"af-kanban-progress-track"}).createDiv({cls:"af-kanban-progress-bar af-kanban-progress-bar-real"}),m=(Date.now()-d)/1e3,f=Math.min(95,m/l*100);p.setCssStyles({width:`${f}%`});let g=n.createDiv({cls:"af-kanban-card-footer"}),w=g.createSpan({cls:"af-kanban-card-schedule"});T(w,"loader-2","af-meta-icon");let y=Math.round(m),v=w.createSpan({text:` ${y}s / ${l}s`}),k=g.createEl("button",{cls:"af-kanban-stop-btn"});(0,Z.setIcon)(k,"square"),k.title="Stop task",k.onclick=b=>{b.stopPropagation(),this.plugin.runtime.abortAgentRun(s.agent),new Z.Notice(`Stopped task "${s.taskId}"`)},this.runningCardTickers.push(()=>{let b=(Date.now()-d)/1e3,P=Math.min(95,b/l*100);p.setCssStyles({width:`${P}%`}),v.setText(` ${Math.round(b)}s / ${l}s`)}),this.runningCardInterval===void 0&&(this.runningCardInterval=window.setInterval(()=>{for(let b of this.runningCardTickers)b()},1e3))}renderKanbanCompletedCard(t,s){let n=t.createDiv({cls:"af-kanban-card"});n.createDiv({cls:"af-kanban-card-title",text:s.task});let r=n.createDiv({cls:"af-kanban-card-agent"}),i=r.createSpan({cls:"af-kanban-card-agent-icon"});(0,Z.setIcon)(i,"bot"),r.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let l=n.createDiv({cls:"af-kanban-card-footer"}).createSpan({cls:"af-kanban-card-schedule"});T(l,"check-circle-2","af-meta-icon"),l.appendText(` ${this.formatStarted(s.started)} \xB7 ${this.formatDuration(s.durationSeconds)}`),n.onclick=()=>this.openSlideover(s)}renderKanbanFailedCard(t,s){let n=s.status==="cancelled",r=t.createDiv({cls:`af-kanban-card ${n?"af-kanban-card-cancelled":"af-kanban-card-failed"}`});r.createDiv({cls:"af-kanban-card-title",text:s.task});let i=r.createDiv({cls:"af-kanban-card-agent"}),o=i.createSpan({cls:"af-kanban-card-agent-icon"});(0,Z.setIcon)(o,"bot"),i.createSpan({cls:"af-kanban-card-agent-name",text:s.agent});let l=n?`Stopped after ${s.durationSeconds}s`:s.status==="timeout"?`Timeout after ${s.durationSeconds}s`:At(s.output,60),c=r.createDiv({cls:"af-kanban-card-error"});T(c,n?"square":"alert-triangle","af-meta-icon"),c.appendText(` ${l}`);let d=r.createDiv({cls:"af-kanban-card-footer"}),u=d.createSpan({cls:"af-kanban-card-schedule"});if(T(u,n?"square":"x-circle","af-meta-icon"),u.appendText(` ${this.formatStarted(s.started)}`),!n){let h=d.createEl("button",{cls:"af-btn-sm"});T(h,"refresh-cw","af-btn-icon"),h.appendText(" Retry"),h.onclick=p=>{p.stopPropagation(),this.plugin.runAgentPrompt(s.agent)}}r.onclick=()=>this.openSlideover(s)}renderCreateChannelPage(t){let s=t.createDiv({cls:"af-create-agent-page"});$r(s,this.channelFormDeps())}renderEditChannelPage(t){let s=t.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"radio","No channel selected","");return}let r=this.plugin.runtime.getSnapshot().channels.find(i=>i.name===n);if(!r){this.renderEmptyState(s,"radio","Channel not found",`Channel "${n}" was not found`);return}$r(s,this.channelFormDeps(),r)}channelFormDeps(){return{plugin:this.plugin,navigate:(t,s)=>this.navigate(t,s),addTooltip:(t,s)=>this.addTooltip(t,s),createFormField:(t,s,n,r,i,o)=>this.createFormField(t,s,n,r,i,o),markSubmitBusy:(t,s,n,r)=>this.markSubmitBusy(t,s,n,r)}}baseFormDeps(){return{plugin:this.plugin,addTooltip:(t,s)=>this.addTooltip(t,s),createFormField:(t,s,n,r,i,o)=>this.createFormField(t,s,n,r,i,o),markSubmitBusy:(t,s,n,r)=>this.markSubmitBusy(t,s,n,r)}}agentFormDeps(){return{...this.baseFormDeps(),navigate:(t,s)=>this.navigate(t,s),renderAgentAvatar:(t,s)=>this.renderAgentAvatar(t,s)}}taskFormDeps(){return{...this.baseFormDeps(),navigate:(t,s)=>this.navigate(t,s)}}skillFormDeps(){return{...this.baseFormDeps(),navigate:t=>this.navigate(t)}}mcpFormDeps(){return{...this.baseFormDeps(),navigate:t=>this.navigate(t)}}basePageDeps(){return{plugin:this.plugin,renderEmptyState:(t,s,n,r,i)=>this.renderEmptyState(t,s,n,r,i)}}agentsPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s),healthToClass:t=>this.healthToClass(t),renderAgentAvatar:(t,s)=>this.renderAgentAvatar(t,s),renderAgentStat:(t,s,n)=>this.renderAgentStat(t,s,n),formatTokenCount:t=>qr(t),cronToHuman:t=>Rc(t),timeUntil:t=>this.timeUntil(t)}}runsPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s),openSlideover:t=>this.openSlideover(t),formatStarted:t=>this.formatStarted(t),formatDuration:t=>this.formatDuration(t),statusToBadgeClass:t=>this.statusToBadgeClass(t),statusToIconName:t=>this.statusToIconName(t),statusToBadgeText:t=>this.statusToBadgeText(t)}}skillsPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s)}}approvalsPageDeps(){return{...this.basePageDeps(),formatStarted:t=>this.formatStarted(t),rerender:()=>this.render()}}channelsPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s),renderAgentStat:(t,s,n)=>this.renderAgentStat(t,s,n)}}mcpPageDeps(){return{...this.basePageDeps(),navigate:t=>this.navigate(t),renderDetailRow:(t,s,n)=>this.renderDetailRow(t,s,n),rerender:()=>this.render(),contentEl:this.contentEl,mcpProbeCache:this.mcpProbeCache,authenticatingServers:this.authenticatingServers}}agentDetailPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s),healthToClass:t=>this.healthToClass(t),renderAgentAvatar:(t,s)=>this.renderAgentAvatar(t,s),renderStatCard:(t,s,n,r,i,o)=>this.renderStatCard(t,s,n,r,i,o),combinedTotals:(t,s)=>this.combinedTotals(t,s),renderTimelineItem:(t,s)=>this.renderTimelineItem(t,s),renderConfigRow:(t,s,n)=>this.renderConfigRow(t,s,n),statusToTimelineClass:t=>this.statusToTimelineClass(t),statusToIconName:t=>this.statusToIconName(t),statusToBadgeClass:t=>this.statusToBadgeClass(t),statusToBadgeText:t=>this.statusToBadgeText(t),formatStarted:t=>this.formatStarted(t),formatDuration:t=>this.formatDuration(t),formatTokenCount:t=>qr(t),cronToHuman:t=>Rc(t),timeUntil:t=>this.timeUntil(t),openSlideover:t=>this.openSlideover(t),openChatSlideover:t=>this.openChatSlideover(t),getDetailTab:()=>this.agentDetailTab,setDetailTab:t=>{this.agentDetailTab=t},rerender:()=>this.render()}}taskDetailPageDeps(){return{...this.basePageDeps(),navigate:(t,s)=>this.navigate(t,s),renderConfigRow:(t,s,n)=>this.renderConfigRow(t,s,n),renderTimelineItem:(t,s)=>this.renderTimelineItem(t,s),humanizeCron:t=>this.humanizeCron(t),formatStarted:t=>this.formatStarted(t)}}handleSearch(t,s){if(s.querySelector(".af-search-results")?.remove(),t.length<2)return;let n=t.toLowerCase(),r=this.plugin.runtime.getSnapshot(),i=this.plugin.runtime.getRecentRuns(),o=[];for(let c of r.agents)(c.name.toLowerCase().includes(n)||(c.description?.toLowerCase().includes(n)??!1))&&o.push({label:`Agent: ${c.name}`,icon:"bot",action:()=>this.navigate("agent-detail",c.name)});for(let c of r.tasks)(c.taskId.toLowerCase().includes(n)||c.body.toLowerCase().includes(n))&&o.push({label:`Task: ${c.taskId}`,icon:"circle-dot",action:()=>this.navigate("task-detail",c.taskId)});for(let c of r.skills)c.name.toLowerCase().includes(n)&&o.push({label:`Skill: ${c.name}`,icon:"puzzle",action:()=>this.navigate("edit-skill",c.name)});for(let c of i.slice(0,20))c.output.toLowerCase().includes(n)&&o.push({label:`Run: ${c.agent} / ${c.task}`,icon:"scroll-text",action:()=>this.openSlideover(c)});let l=s.createDiv({cls:"af-search-results"});if(o.length===0){l.createDiv({cls:"af-search-result-empty",text:`No results for "${t}"`});return}for(let c of o.slice(0,10)){let d=l.createDiv({cls:"af-search-result-item"});T(d,c.icon,"af-search-result-icon"),d.createSpan({text:c.label}),d.onclick=()=>{l.remove(),c.action()}}o.length>10&&l.createDiv({cls:"af-search-result-footer",text:`Showing 10 of ${o.length} results`})}openChatSlideover(t){this.plugin.openChatView(t.name)}openSlideover(t){this.contentEl.querySelector(".af-slideover-overlay")?.remove();let s=this.contentEl.createDiv({cls:"af-slideover-overlay"}),n=s.createDiv({cls:"af-slideover"}),r=n.createDiv({cls:"af-slideover-header"});r.createDiv({cls:"af-slideover-title",text:"Run Details"});let i=r.createEl("button",{cls:"clickable-icon"});(0,Z.setIcon)(i,"cross"),i.onclick=()=>s.remove();let o=n.createDiv({cls:"af-slideover-body"}),l=o.createDiv({cls:"af-slideover-section"});l.createDiv({cls:"af-slideover-section-title",text:"METADATA"}),this.renderDetailRow(l,"Run ID",t.runId.slice(0,8)),this.renderDetailRow(l,"Agent",t.agent),this.renderDetailRow(l,"Task",t.task);let c=l.createDiv({cls:"af-detail-row"});c.createSpan({cls:"af-detail-label",text:"Status"});let u=c.createSpan({cls:"af-detail-value"}).createSpan({cls:`af-status-badge ${this.statusToBadgeClass(t.status)}`}),h=u.createSpan();(0,Z.setIcon)(h,this.statusToIconName(t.status)),u.appendText(` ${this.statusToBadgeText(t.status)}`),this.renderDetailRow(l,"Started",t.started),this.renderDetailRow(l,"Duration",this.formatDuration(t.durationSeconds)),this.renderDetailRow(l,"Tokens",t.tokensUsed?t.tokensUsed.toLocaleString():"\u2014");{let k={task:"from task override",agent:"from agent",settings:"from settings default","cli-default":"CLI default"},b=t.modelSource?` (${k[t.modelSource]??t.modelSource})`:"",P=t.concreteModel&&t.concreteModel!==t.model?` \u2192 ${t.concreteModel}`:"";this.renderDetailRow(l,"Model",`${t.model}${P}${b}`)}let p=5e4,m=k=>k.length>p?k.slice(0,p)+`
|
|
12032
12020
|
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
...`,rows:"6"}});ge.value=a.examplesBody,ge.addEventListener("input",()=>{d.examplesBody=ge.value});let X=s.createDiv({cls:"af-create-footer"}),W=X.createEl("button",{cls:"af-btn-sm danger"});R(W,"trash-2","af-btn-icon"),W.appendText(" Delete"),W.onclick=async()=>{await this.plugin.repository.deleteSkill(a.name),new b.Notice(`Skill "${a.name}" deleted.`),await new Promise(G=>window.setTimeout(G,200)),await this.plugin.refreshFromVault(),this.navigate("skills")},X.createDiv({cls:"af-toolbar-spacer"});let K=X.createEl("button",{cls:"af-btn-sm",text:"Cancel"});K.onclick=()=>this.navigate("skills");let ne=X.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(ne,"check","af-btn-icon"),ne.appendText(" Save Changes"),ne.onclick=async()=>{let G=ee=>ee.split(",").map(Q=>Q.trim()).filter(Boolean);try{await this.plugin.repository.updateSkill(a.name,{description:d.description.trim(),tags:G(d.tags),body:d.body.trim(),toolsBody:d.toolsBody.trim(),referencesBody:d.referencesBody.trim(),examplesBody:d.examplesBody.trim()}),new b.Notice(`Skill "${a.name}" updated.`),await this.plugin.refreshFromVault(),this.navigate("skills")}catch(ee){let Q=ee instanceof Error?ee.message:String(ee);new b.Notice(`Failed to update skill: ${Q}`)}}}renderAgentMcpPicker(e,s){e.createDiv({cls:"af-form-hint",text:"Servers from the MCP Servers tab. Checked servers are available to this agent on any adapter (Claude or Codex). Leave all unchecked to grant every enabled server."});let n=this.plugin.repository.getMcpServers();if(n.length===0){let i=e.createDiv({cls:"af-form-hint"});i.appendText("No MCP servers registered yet. ");let o=i.createEl("a",{cls:"af-link",text:"Add one in the MCP Servers tab."});o.onclick=c=>{c.preventDefault(),this.navigate("mcp")};return}let a=e.createDiv({cls:"af-create-skills-grid"});for(let i of n){let o=a.createDiv({cls:"af-mcp-agent-item"}),c=o.createEl("input",{cls:"af-form-toggle",attr:{type:"checkbox"}});c.checked=s.has(i.name),c.addEventListener("change",()=>{c.checked?s.add(i.name):s.delete(i.name)});let h=o.createDiv({cls:"af-mcp-agent-label"}).createDiv({cls:"af-mcp-agent-name-row"}),d=h.createSpan({cls:`af-mcp-status-dot ${i.enabled?"idle":"disabled"}`});d.title=i.enabled?"enabled":"disabled",h.createSpan({cls:"af-create-skill-name",text:i.name}),h.createSpan({cls:"af-mcp-agent-tool-count",text:i.type}),i.enabled||h.createSpan({cls:"af-mcp-agent-tool-count af-muted",text:"disabled"})}}renderMcpPage(e){let s=e.createDiv({cls:"af-agents-page"}),n=s.createDiv({cls:"af-agents-toolbar"});n.createDiv({cls:"af-page-title",text:"MCP Servers"}),n.createDiv({cls:"af-toolbar-spacer"});let a=n.createEl("button",{cls:"af-btn-sm primary"});R(a,"plus","af-btn-icon"),a.appendText(" Add Server"),a.onclick=()=>this.navigate("add-mcp-server");let i=this.plugin.repository.getMcpServers();if(i.length===0){this.renderEmptyState(s,"plug","No MCP servers registered","Click 'Add Server' above to register one.");return}let o=s.createDiv({cls:"af-agents-grid"});for(let c of i)this.renderMcpCard(o,c)}mcpProbeCache=new Map;mcpHasToken(e){return this.plugin.mcpAuth.hasToken(e.name)}mcpNeedsAuth(e){return e.type!=="stdio"&&(e.auth==="oauth"||e.auth==="bearer")&&!this.mcpHasToken(e)}renderMcpCard(e,s){let n=e.createDiv({cls:`af-mcp-card${s.enabled?"":" af-mcp-card-disabled"}`}),a=this.mcpNeedsAuth(s),i=n.createDiv({cls:"af-agent-card-header"}),o=s.enabled?a?"pending":"idle":"disabled",c=i.createDiv({cls:`af-agent-card-avatar ${o}`});(0,b.setIcon)(c,"plug");let l=i.createDiv({cls:"af-agent-card-titleblock"});l.createDiv({cls:"af-agent-card-name",text:s.name});let h=l.createDiv({cls:"af-agent-card-desc af-mcp-meta"});h.createSpan({cls:"af-mcp-type-badge",text:s.type}),s.source==="imported"&&h.createSpan({cls:"af-badge",text:"imported"});let d=i.createDiv({cls:`af-agent-card-toggle${s.enabled?" on":""}`});d.onclick=g=>{g.stopPropagation(),this.plugin.repository.setMcpServerEnabled(s.name,!s.enabled).then(async()=>{await this.plugin.refreshFromVault(),this.render()})};let u=n.createDiv({cls:`af-mcp-status-badge ${s.enabled?a?"needs-auth":"connected":"disabled"}`}),p=u.createSpan();if(s.enabled?a?((0,b.setIcon)(p,"alert-circle"),u.createSpan({text:" Needs auth"})):((0,b.setIcon)(p,"check-circle"),u.createSpan({text:s.type==="stdio"?" Enabled":" Authenticated"})):((0,b.setIcon)(p,"pause"),u.createSpan({text:" Disabled"})),s.description){let g=this.truncateDescription(s.description,120);n.createDiv({cls:"af-mcp-description",text:g})}let m=s.url??s.command??"";m&&n.createDiv({cls:"af-mcp-command",text:Wt(m,60)});let f=this.mcpProbeCache.get(s.name);if(f&&f.length>0){let g=n.createDiv({cls:"af-mcp-tool-footer"}),y=g.createDiv({cls:"af-mcp-tool-count"}),v=y.createSpan();(0,b.setIcon)(v,"wrench"),y.createSpan({text:` ${f.length} tools`});let k=g.createDiv({cls:"af-mcp-tool-chips"});for(let w of f.slice(0,4))k.createSpan({cls:"af-mcp-tool-chip",text:w.name});f.length>4&&k.createSpan({cls:"af-mcp-tool-chip af-mcp-tool-chip-more",text:`+${f.length-4}`})}if(this.authenticatingServers.has(s.name)){let y=n.createDiv({cls:"af-mcp-auth-row"}).createEl("button",{cls:"af-btn-sm primary",attr:{disabled:"true"}}),v=y.createSpan({cls:"af-spin"});(0,b.setIcon)(v,"loader-2"),y.appendText(" Authenticating\u2026")}else if(s.enabled&&a&&s.auth==="oauth"){let y=n.createDiv({cls:"af-mcp-auth-row"}).createEl("button",{cls:"af-btn-sm primary"}),v=y.createSpan();(0,b.setIcon)(v,"key"),y.appendText(" Authenticate"),y.onclick=k=>{k.stopPropagation(),this.authenticateMcpServer(s)}}n.onclick=()=>this.openMcpDetailSlideover(s)}async authenticateMcpServer(e){if(!e.url){new b.Notice("No URL found for this server \u2014 can't authenticate.");return}this.authenticatingServers.add(e.name),this.render(),new b.Notice(`Authenticating ${e.name}\u2026 Complete authorization in your browser.`,1e4);try{let s=e.type==="sse"?"sse":"http";await this.plugin.mcpManager.authenticateServer(e.name,e.url,s),new b.Notice(`${e.name} authenticated successfully!`)}catch(s){let n=s instanceof Error?s.message:String(s);new b.Notice(`Authentication failed: ${n}`,8e3)}finally{this.authenticatingServers.delete(e.name),this.render()}}async probeMcpServer(e){try{let s=await this.plugin.mcpManager.probeServer(e);this.mcpProbeCache.set(e.name,s),s.length===0&&new b.Notice(`No tools discovered for ${e.name}.`)}catch(s){let n=s instanceof Error?s.message:String(s);new b.Notice(`Probe failed: ${n}`)}}truncateDescription(e,s){let n=ye(e)[0]??e,a=n.split(/(?<=[.!?])\s/)[0]??n,i=a.length<n.length?a:n;return i.length<=s?i:i.slice(0,s-1)+"\u2026"}openMcpDetailSlideover(e){this.contentEl.querySelector(".af-slideover-overlay")?.remove();let s=this.contentEl.createDiv({cls:"af-slideover-overlay"}),n=s.createDiv({cls:"af-slideover"}),a=n.createDiv({cls:"af-slideover-header"});a.createDiv({cls:"af-slideover-title",text:e.name});let i=a.createEl("button",{cls:"clickable-icon"});(0,b.setIcon)(i,"cross"),i.onclick=()=>s.remove(),s.onclick=y=>{y.target===s&&s.remove()};let o=n.createDiv({cls:"af-slideover-body"});if(e.description){let y=o.createDiv({cls:"af-slideover-section"});y.createDiv({cls:"af-slideover-section-title",text:"DESCRIPTION"}),y.createDiv({cls:"af-mcp-detail-description",text:e.description})}let c=o.createDiv({cls:"af-slideover-section"});c.createDiv({cls:"af-slideover-section-title",text:"SERVER INFO"}),this.renderDetailRow(c,"Name",e.name),this.renderDetailRow(c,"Transport",e.type),this.renderDetailRow(c,"Enabled",e.enabled?"yes":"no"),e.type!=="stdio"&&(this.renderDetailRow(c,"Auth",e.auth??"none"),this.renderDetailRow(c,"Authenticated",this.mcpHasToken(e)?"yes":"no")),e.source&&this.renderDetailRow(c,"Source",e.source),e.url&&this.renderDetailRow(c,"URL",e.url),e.command&&this.renderDetailRow(c,"Command",e.command),e.args&&e.args.length>0&&this.renderDetailRow(c,"Args",e.args.join(" "));let l=this.mcpProbeCache.get(e.name)??[],h=o.createDiv({cls:"af-slideover-section"});h.createDiv({cls:"af-slideover-section-title"}).setText(`TOOLS (${l.length})`);let u=h.createEl("button",{cls:"af-btn-sm"}),p=u.createSpan();if((0,b.setIcon)(p,"wrench"),u.appendText(" Probe tools"),u.onclick=async()=>{u.disabled=!0,u.setText(" Probing\u2026"),await this.probeMcpServer(e),s.remove(),this.openMcpDetailSlideover(e)},l.length>0)for(let y of l){let v=h.createDiv({cls:"af-mcp-tool-detail"}),k=v.createDiv({cls:"af-mcp-tool-detail-header"}),w=k.createSpan({cls:"af-mcp-tool-detail-name"}),S=w.createSpan();if((0,b.setIcon)(S,"wrench"),w.createSpan({text:` ${y.name}`}),y.inputSchema){let T=y.inputSchema.required??[];T.length>0&&k.createSpan({cls:"af-mcp-tool-param-count",text:`${T.length} param${T.length!==1?"s":""}`})}if(y.description){let T=ye(y.description).filter(O=>O.trim()),_=T.slice(0,2).join(" ").trim();if(T.length>2){let O=v.createEl("details",{cls:"af-mcp-tool-detail-desc"});O.createEl("summary",{text:this.truncateDescription(_,200)}),O.createDiv({cls:"af-mcp-tool-detail-full",text:y.description})}else v.createDiv({cls:"af-mcp-tool-detail-desc",text:_})}if(y.inputSchema){let T=y.inputSchema.properties,_=new Set(y.inputSchema.required??[]);if(T&&Object.keys(T).length>0){let D=v.createDiv({cls:"af-mcp-tool-params"});for(let[O,C]of Object.entries(T)){let E=D.createDiv({cls:"af-mcp-tool-param"});E.createSpan({cls:"af-mcp-tool-param-name",text:O}),C.type&&E.createSpan({cls:"af-mcp-tool-param-type",text:C.type}),_.has(O)&&E.createSpan({cls:"af-mcp-tool-param-required",text:"required"}),C.description&&E.createSpan({cls:"af-mcp-tool-param-desc",text:Wt(C.description,80)})}}}}else h.createDiv({cls:"af-form-hint",text:'Click "Probe tools" to discover the tools this server exposes.'});let m=o.createDiv({cls:"af-slideover-section"});if(m.createDiv({cls:"af-slideover-section-title",text:"ACTIONS"}),e.enabled&&e.url&&e.auth==="oauth"&&!this.mcpHasToken(e)){let y=m.createEl("button",{cls:"af-btn-sm primary"}),v=y.createSpan();(0,b.setIcon)(v,"key"),y.appendText(" Authenticate"),y.onclick=()=>{s.remove(),this.authenticateMcpServer(e)}}let f=m.createEl("button",{cls:"af-btn-sm danger"}),g=f.createSpan();(0,b.setIcon)(g,"trash-2"),f.appendText(" Remove Server"),f.onclick=async()=>{try{await this.plugin.repository.deleteMcpServer(e.name),this.plugin.mcpAuth.removeToken(e.name),this.mcpProbeCache.delete(e.name),new b.Notice(`Server "${e.name}" removed.`),s.remove(),await this.plugin.refreshFromVault(),this.render()}catch(y){let v=y instanceof Error?y.message:String(y);new b.Notice(`Failed to remove server: ${v}`)}}}renderAddMcpServerPage(e){let s=e.createDiv({cls:"af-create-agent-page"}),n=s.createDiv({cls:"af-detail-header"}),a=n.createDiv({cls:"af-detail-header-left"}),i=a.createDiv({cls:"af-agent-card-avatar idle"});(0,b.setIcon)(i,"plus");let o=a.createDiv();o.createDiv({cls:"af-detail-header-name",text:"Add MCP Server"}),o.createDiv({cls:"af-detail-header-desc",text:"Register a new MCP server for agents to use"});let c=n.createDiv({cls:"af-detail-header-actions"}),l={name:"",transport:"stdio",description:"",command:"",args:"",envVars:"",url:"",headers:"",auth:"none",bearerToken:""},h=s.createDiv({cls:"af-create-form"}),d=h.createDiv({cls:"af-create-section"}),u=d.createDiv({cls:"af-create-section-header"}),p=u.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(p,"plug"),u.createSpan({text:"Server Details"}),this.createFormField(d,"Name","my-server","Unique name for this MCP server",W=>{l.name=W});let m=d.createDiv({cls:"af-form-row"}),f=m.createDiv({cls:"af-form-label"});f.setText("Transport"),this.addTooltip(f,"stdio: local process, http/sse: remote server");let g=m.createEl("select",{cls:"af-form-select"});g.createEl("option",{text:"stdio",attr:{value:"stdio"}}),g.createEl("option",{text:"http",attr:{value:"http"}}),g.createEl("option",{text:"sse",attr:{value:"sse"}}),this.createFormField(d,"Description","What this server does (optional)","Shown on the server card",W=>{l.description=W});let y=h.createDiv({cls:"af-create-section"}),v=y.createDiv({cls:"af-create-section-header"}),k=v.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(k,"terminal"),v.createSpan({text:"Process Configuration"}),this.createFormField(y,"Command","npx @anthropic-ai/mcp-server-memory","The command to run",W=>{l.command=W}),this.createFormField(y,"Arguments","--port 3000","Space-separated arguments (optional)",W=>{l.args=W});let w=y.createDiv({cls:"af-form-label"});w.setText("Environment variables"),this.addTooltip(w,"One KEY=VALUE per line");let S=y.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:`API_KEY=sk-...
|
|
12036
|
-
DEBUG=true`,rows:"3"}});S.addEventListener("input",()=>{l.envVars=S.value});let T=h.createDiv({cls:"af-create-section"}),_=T.createDiv({cls:"af-create-section-header"}),D=_.createSpan({cls:"af-create-section-icon"});(0,b.setIcon)(D,"globe"),_.createSpan({text:"Remote Server Configuration"}),this.createFormField(T,"URL","https://mcp.example.com/sse","Server endpoint URL",W=>{l.url=W});let O=T.createDiv({cls:"af-form-label"});O.setText("Custom headers"),this.addTooltip(O,"One Header: Value per line (optional, non-secret)");let C=T.createEl("textarea",{cls:"af-create-prompt-textarea",attr:{placeholder:"X-Custom-Header: value",rows:"2"}});C.addEventListener("input",()=>{l.headers=C.value});let E=T.createDiv({cls:"af-form-row"}),P=E.createDiv({cls:"af-form-label"});P.setText("Authentication"),this.addTooltip(P,"none, a static bearer token, or OAuth (authenticate after saving)");let N=E.createEl("select",{cls:"af-form-select"});N.createEl("option",{text:"None",attr:{value:"none"}}),N.createEl("option",{text:"Bearer token",attr:{value:"bearer"}}),N.createEl("option",{text:"OAuth",attr:{value:"oauth"}});let M=T.createDiv({cls:"af-form-row"}),U=M.createDiv({cls:"af-form-label"});U.setText("Bearer token"),this.addTooltip(U,"Stored securely in the OS keychain, never written to the vault");let $=M.createEl("input",{cls:"af-form-input",attr:{type:"password",placeholder:"sk-\u2026"}});$.addEventListener("input",()=>{l.bearerToken=$.value});let Z=()=>{M.setCssStyles({display:l.auth==="bearer"?"":"none"})};N.addEventListener("change",()=>{l.auth=N.value,Z()}),Z();let de=()=>{y.setCssStyles({display:l.transport==="stdio"?"":"none"}),T.setCssStyles({display:l.transport!=="stdio"?"":"none"})};g.addEventListener("change",()=>{l.transport=g.value,de()}),de();let me=s.createDiv({cls:"af-create-footer"}),ge=me.createEl("button",{cls:"af-btn-sm",text:"Cancel"});ge.onclick=()=>this.navigate("mcp");let X=me.createEl("button",{cls:"af-btn-sm primary af-create-submit"});R(X,"plus","af-btn-icon"),X.appendText(" Add Server"),X.onclick=async()=>{let W=l.name.trim();if(!W){new b.Notice("Server name is required.");return}if(l.transport==="stdio"){if(!l.command.trim()){new b.Notice("Command is required for stdio servers.");return}}else if(!l.url.trim()){new b.Notice("URL is required for HTTP/SSE servers.");return}let K={};if(l.envVars.trim())for(let Q of ye(l.envVars)){let ae=Q.trim();if(!ae)continue;let ve=ae.indexOf("=");if(ve<=0){new b.Notice(`Invalid env var: ${ae}`);return}K[ae.slice(0,ve)]=ae.slice(ve+1)}let ne={};if(l.headers.trim())for(let Q of ye(l.headers)){let ae=Q.trim();if(!ae)continue;let ve=ae.indexOf(":");if(ve<=0){new b.Notice(`Invalid header: ${ae}`);return}ne[ae.slice(0,ve).trim()]=ae.slice(ve+1).trim()}let G=l.args.trim()?l.args.trim().split(/\s+/):void 0;if(this.plugin.repository.getMcpServerByName(W)){new b.Notice(`An MCP server named "${W}" already exists.`);return}if(l.transport!=="stdio"&&l.auth==="bearer"&&!l.bearerToken.trim()){new b.Notice("Enter a bearer token, or choose a different auth method.");return}X.disabled=!0,X.setText("Adding...");let ee={name:W,type:l.transport,enabled:!0,source:"manual",status:"disconnected",scope:"user",tools:[],toolDetails:[]};l.transport==="stdio"?(ee.command=l.command.trim(),G&&(ee.args=G),Object.keys(K).length>0&&(ee.env=K)):(ee.url=l.url.trim(),Object.keys(ne).length>0&&(ee.headers=ne),ee.auth=l.auth);try{await this.plugin.repository.saveMcpServer(ee,l.description.trim()),l.transport!=="stdio"&&l.auth==="bearer"&&l.bearerToken.trim()&&this.plugin.mcpAuth.storeStaticToken(W,l.bearerToken.trim()),new b.Notice(`Server "${W}" added.`),await this.plugin.refreshFromVault(),this.navigate("mcp")}catch(Q){let ae=Q instanceof Error?Q.message:String(Q);new b.Notice(`Failed to add server: ${ae}`),X.disabled=!1,X.setText(""),R(X,"plus","af-btn-icon"),X.appendText(" Add Server")}}}createFormField(e,s,n,a,i,o){let c=e.createDiv({cls:"af-form-row"}),l=c.createDiv({cls:"af-form-label"});l.setText(s),a&&this.addTooltip(l,a);let h=c.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:n}});o!==void 0&&(h.value=o),h.addEventListener("input",()=>i(h.value))}addTooltip(e,s){let n=e.createSpan({cls:"af-form-tooltip"});(0,b.setIcon)(n,"info"),n.createSpan({cls:"af-tooltip-text",text:s})}};function Qo(r){switch(r){case"connected":return"idle";case"connecting":case"reconnecting":return"pending";case"needs-auth":case"error":return"error";case"stopped":case"disabled":default:return"disabled"}}function Ka(r){return r>=1e6?`${(r/1e6).toFixed(1)}M`:r>=1e4?`${Math.round(r/1e3)}K`:r>=1e3?`${(r/1e3).toFixed(1)}K`:String(r)}function xh(r){if(!r?.trim())return"not set";let t={"*/5 * * * *":"Every 5 minutes","*/10 * * * *":"Every 10 minutes","*/15 * * * *":"Every 15 minutes","*/30 * * * *":"Every 30 minutes","0 * * * *":"Every hour","0 */2 * * *":"Every 2 hours","0 */4 * * *":"Every 4 hours","0 */6 * * *":"Every 6 hours","0 */12 * * *":"Every 12 hours"};if(t[r])return t[r];let e=r.trim().split(/\s+/);if(e.length===5){let[s,n,a,,i]=e;if(a==="*"&&n&&s){let o=Number(n),c=Number(s);if(!isNaN(o)&&!isNaN(c)){let l=o>=12?"PM":"AM",d=`${o===0?12:o>12?o-12:o}:${String(c).padStart(2,"0")} ${l}`;return i==="*"?`Daily at ${d}`:i==="1-5"?`Weekdays at ${d}`:`${d} on days ${i}`}}}return r}function Sh(r){switch(r){case"connected":return"green";case"connecting":case"reconnecting":return"blue";case"needs-auth":case"error":return"red";case"stopped":case"disabled":default:return""}}var z=require("obsidian");function qn(r,t){return`${r}::${t}`}function tl(){return Math.random().toString(16).slice(2,10)}function sl(){return`New chat ${new Date().toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}`}function Ch(r){let t=new Date(r).getTime();if(!Number.isFinite(t))return"";let e=Date.now()-t,s=60*1e3,n=60*s,a=24*n;return e<s?"just now":e<n?`${Math.floor(e/s)}m`:e<a?`${Math.floor(e/n)}h`:e<2*a?"yesterday":e<7*a?`${Math.floor(e/a)}d`:new Date(t).toLocaleDateString(void 0,{month:"short",day:"numeric"})}var Th=480,Ja="http://www.w3.org/2000/svg";function _h(r){let t=activeDocument.createElementNS(Ja,"svg");t.setAttribute("class","svg-icon af-convo-toggle-icon"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round");let e=activeDocument.createElementNS(Ja,"rect");for(let[n,a]of Object.entries({x:"1",y:"2",width:"22",height:"20",rx:"4"}))e.setAttribute(n,a);let s=activeDocument.createElementNS(Ja,"rect");s.setAttribute("class","af-convo-toggle-bar");for(let[n,a]of Object.entries({x:"4",y:"5",width:"2",height:"14",rx:"2",fill:"currentColor"}))s.setAttribute(n,a);t.appendChild(e),t.appendChild(s),r.appendChild(t)}var os=class r extends z.ItemView{constructor(e,s){super(e);this.plugin=s}selectedAgentName=null;selectedConversationId="";sessions=new Map;conversationsCache=[];convoPanelEl=null;collapseBtn=null;convoPanelCollapsed=!1;userToggledCollapse=!1;resizeObserver=null;headerEl;agentSelect;messagesEl;messagesInner;textarea;sendBtn;attachStopBtn;isInStopMode=!1;attachedFiles=[];attachedImages=[];pillsRow;activityEl=null;streamingDot=null;activityUnsub=null;statsEl;statsUnsub=null;statsSourceSession=null;threadExpanded=new Map;getViewType(){return rt}getDisplayText(){if(!this.selectedAgentName)return"Agent Chat";let e=this.getCurrentConversationName();return!e||this.conversationsCache.length<=1?`Chat: ${this.selectedAgentName}`:`Chat: ${this.selectedAgentName} \xB7 ${e}`}getIcon(){return"message-circle"}getState(){return{agentName:this.selectedAgentName??null,conversationId:this.selectedConversationId,convoPanelCollapsed:this.convoPanelCollapsed}}async setState(e,s){await super.setState(e,s);let n=typeof e?.conversationId=="string"&&e.conversationId?e.conversationId:void 0;typeof e?.convoPanelCollapsed=="boolean"&&(this.convoPanelCollapsed=e.convoPanelCollapsed,this.userToggledCollapse=!0,this.applyCollapsedClass()),e?.agentName&&typeof e.agentName=="string"&&this.selectAgent(e.agentName,n)}getCurrentConversationName(){return this.conversationsCache.find(s=>s.id===this.selectedConversationId)?.name??""}async onOpen(){this.plugin.subscribeView(this),this.buildShell(),await this.render(),this.observeContainerWidth()}async onClose(){for(let{session:e}of this.sessions.values())e.abort();this.sessions.clear(),this.statsUnsub?.(),this.statsUnsub=null,this.activityUnsub?.(),this.activityUnsub=null,this.resizeObserver?.disconnect(),this.resizeObserver=null,this.plugin.unsubscribeView(this)}observeContainerWidth(){typeof ResizeObserver>"u"||(this.resizeObserver=new ResizeObserver(e=>{if(!this.userToggledCollapse)for(let s of e){let a=s.contentRect.width<Th;a!==this.convoPanelCollapsed&&(this.convoPanelCollapsed=a,this.applyCollapsedClass())}}),this.resizeObserver.observe(this.contentEl))}selectAgent(e,s){if(s){let n=this.plugin.app.workspace.getLeavesOfType(rt);for(let a of n)if(a.view!==this&&a.view instanceof r&&a.view.selectedAgentName===e&&a.view.selectedConversationId===s){this.plugin.app.workspace.revealLeaf(a);return}}this.selectedAgentName=e,s&&(this.selectedConversationId=s),this.agentSelect&&(this.agentSelect.value=e),this.leaf.updateHeader(),this.switchToAgent(e,s)}buildShell(){let e=this.contentEl;e.empty(),e.addClass("af-root");let s=e.createDiv({cls:"af-chat-view-container"});this.headerEl=s.createDiv({cls:"af-chat-view-header"}),this.collapseBtn=this.headerEl.createEl("button",{cls:"clickable-icon af-chat-convo-collapse-btn",attr:{title:"Toggle conversations panel","aria-label":"Toggle conversations panel"}}),_h(this.collapseBtn),this.collapseBtn.toggleClass("is-collapsed",this.convoPanelCollapsed),this.collapseBtn.onclick=()=>this.toggleConvoPanel(),this.agentSelect=this.headerEl.createEl("select",{cls:"af-chat-view-agent-select"});let n=this.headerEl.createEl("button",{cls:"af-btn-sm af-chat-view-new-btn"});R(n,"plus","af-btn-icon"),n.appendText(" New Chat"),n.onclick=()=>void this.handleNewChat();let a=s.createDiv({cls:"af-chat-view-body"});this.convoPanelEl=a.createDiv({cls:"af-chat-convo-panel"}),this.convoPanelCollapsed&&this.convoPanelEl.addClass("collapsed");let i=a.createDiv({cls:"af-chat-main"});this.agentSelect.onchange=()=>{let h=this.agentSelect.value;h&&(this.selectedConversationId="",this.textarea.disabled=!1,this.textarea.placeholder="Message the agent\u2026 (Shift+Enter for newline)",this.switchToAgent(h))},this.messagesEl=i.createDiv({cls:"af-chat-messages"}),this.messagesInner=this.messagesEl.createDiv({cls:"af-chat-messages-inner"});let o=i.createDiv({cls:"af-chat-input-area"});this.pillsRow=o.createDiv({cls:"af-chat-pills-row"}),this.pillsRow.setCssStyles({display:"none"});let c=o.createDiv({cls:"af-chat-input-row"});this.attachStopBtn=c.createEl("button",{cls:"af-chat-attach-btn"}),R(this.attachStopBtn,"plus","af-btn-icon"),this.attachStopBtn.title="Attach active document",this.attachStopBtn.onclick=()=>{this.isInStopMode?this.handleStop():this.attachActiveDocument()},this.textarea=c.createEl("textarea",{cls:"af-chat-input",attr:{placeholder:"Message the agent\u2026 (Shift+Enter for newline)",rows:"1"}}),this.sendBtn=c.createEl("button",{cls:"af-chat-send-btn"}),R(this.sendBtn,"arrow-up","af-btn-icon"),this.sendBtn.setCssStyles({display:"none"});let l=()=>{this.textarea.setCssStyles({height:"auto"});let h=Math.min(this.textarea.scrollHeight,160);this.textarea.setCssStyles({height:`${h}px`}),this.textarea.setCssStyles({overflowY:this.textarea.scrollHeight>160?"auto":"hidden"}),this.sendBtn.setCssStyles({display:this.textarea.value.trim()?"flex":"none"})};this.textarea.addEventListener("input",l),this.textarea.addEventListener("focus",()=>{let h=this.getCurrentSession();h&&this.setStatsSource(h.session)}),this.sendBtn.onclick=()=>void this.handleSend(),this.textarea.onkeydown=h=>{h.key==="Enter"&&!h.shiftKey&&!h.isComposing&&(h.preventDefault(),this.handleSend())},this.textarea.addEventListener("paste",h=>{let d=h.clipboardData?.items;if(d)for(let u=0;u<d.length;u++){let p=d[u];if(p.type.startsWith("image/")){h.preventDefault();let m=p.getAsFile();m&&this.attachImageBlob(m);return}}}),o.addEventListener("dragover",h=>{h.preventDefault(),h.stopPropagation(),o.addClass("af-chat-input-dragover")}),o.addEventListener("dragleave",()=>{o.removeClass("af-chat-input-dragover")}),o.addEventListener("drop",h=>{h.preventDefault(),h.stopPropagation(),o.removeClass("af-chat-input-dragover");let d=h.dataTransfer?.files;if(d)for(let u=0;u<d.length;u++){let p=d[u];p.type.startsWith("image/")&&this.attachImageBlob(p)}}),this.statsEl=o.createDiv({cls:"af-chat-stats"}),this.renderStats(null)}async render(){this.populateAgentDropdown()}setStatsSource(e){this.statsSourceSession!==e&&(this.statsUnsub?.(),this.statsSourceSession=e,this.statsUnsub=e.onStatsChange(s=>this.renderStats(s)))}renderStats(e){if(this.statsEl.empty(),!e||!e.concreteModel){this.statsEl.createSpan({cls:"af-chat-stats-muted",text:"\xA0"});return}let s=this.statsEl.createSpan({cls:"af-chat-stats-line"});if(s.createSpan({cls:"af-chat-stats-model",text:e.concreteModel}),e.contextWindow&&e.contextTokensUsed){let n=Math.min(100,Math.round(e.contextTokensUsed/e.contextWindow*100)),a=10,i=Math.min(a,Math.max(0,Math.round(n/100*a))),o="\u2593".repeat(i)+"\u2591".repeat(a-i),c=s.createSpan({cls:`af-chat-stats-ctx${n>=80?" warn":""}`});c.createSpan({cls:"af-chat-stats-bar",text:o}),c.createSpan({cls:"af-chat-stats-pct",text:`${n}%`}),c.title=`Context: ${is(e.contextTokensUsed)} / ${is(e.contextWindow)} tokens (${n}%)
|
|
12021
|
+
---
|
|
12022
|
+
*Truncated (${(k.length/1024).toFixed(0)} KB total). Open the run note for full content.*`:k,f=!!(t.finalResult&&t.finalResult.trim()),g=t.output?.trim()??"",w=f&&g.length>0&&g!==t.finalResult.trim();if(f){let k=o.createDiv({cls:"af-slideover-section"});k.createDiv({cls:"af-slideover-section-title",text:"OUTPUT"});let b=k.createDiv({cls:"af-output-block af-compact-md"});if(Z.MarkdownRenderer.render(this.app,m(t.finalResult),b,"",this),w){let P=k.createEl("details",{cls:"af-run-transcript"}),A=P.createEl("summary");(0,Z.setIcon)(A.createSpan({cls:"af-run-transcript-icon"}),"file-text"),A.createSpan({text:"Show full transcript"}),A.createSpan({cls:"af-run-transcript-meta"}).setText(`${(g.length/1024).toFixed(1)} KB`);let E=P.createDiv({cls:"af-output-block af-compact-md af-run-transcript-body"});Z.MarkdownRenderer.render(this.app,m(g),E,"",this)}}else if(g){let k=o.createDiv({cls:"af-slideover-section"});k.createDiv({cls:"af-slideover-section-title",text:"OUTPUT"});let b=k.createDiv({cls:"af-output-block af-compact-md"});Z.MarkdownRenderer.render(this.app,m(g),b,"",this)}if(t.toolsUsed.length>0){let k=o.createDiv({cls:"af-slideover-section"});k.createDiv({cls:"af-slideover-section-title",text:"TOOLS USED"}),k.createDiv({cls:"af-output-block",text:t.toolsUsed.join(`
|
|
12023
|
+
`)})}let y=o.createDiv({cls:"af-slideover-actions"});if(t.filePath){let k=y.createEl("button",{cls:"af-btn-sm"});T(k,"external-link","af-btn-icon"),k.appendText(" Open Run Note"),k.onclick=()=>void this.plugin.openPath(t.filePath)}let v=y.createEl("button",{cls:"af-btn-sm primary"});T(v,"refresh-cw","af-btn-icon"),v.appendText(" Re-run Task"),v.onclick=()=>void this.plugin.runAgentPrompt(t.agent),s.onclick=k=>{k.target===s&&s.remove()}}renderDetailRow(t,s,n){let r=t.createDiv({cls:"af-detail-row"});r.createSpan({cls:"af-detail-label",text:s}),r.createSpan({cls:"af-detail-value af-mono",text:n})}renderEmptyState(t,s,n,r,i){let o=t.createDiv({cls:"af-empty-state"}),l=o.createDiv({cls:"af-empty-icon"});if((0,Z.setIcon)(l,s),o.createDiv({cls:"af-empty-label",text:n}),r&&o.createDiv({cls:"af-empty-sublabel",text:r}),i){let c=o.createEl("button",{cls:"af-btn-sm primary af-empty-action"});T(c,"plus","af-btn-icon"),c.appendText(` ${i.label}`),c.onclick=()=>i.onClick()}}markSubmitBusy(t,s,n,r){return t.disabled=!0,t.setText(s),()=>{t.disabled=!1,t.setText(""),T(t,n,"af-btn-icon"),t.appendText(` ${r}`)}}healthToClass(t){switch(t){case"running":return"running";case"error":return"error";case"pending":return"pending";case"disabled":return"disabled";default:return"idle"}}statusToTimelineClass(t){switch(t){case"success":return"success";case"failure":case"timeout":return"error";case"cancelled":return"warning";case"pending_approval":return"pending";default:return"running"}}statusToIconName(t){switch(t){case"success":return"check-circle-2";case"failure":return"x-circle";case"timeout":return"clock";case"pending_approval":return"shield-check";case"cancelled":return"square";default:return"loader-2"}}statusToBadgeClass(t){switch(t){case"success":return"success";case"failure":return"failure";case"timeout":return"timeout";case"pending_approval":return"pending";case"cancelled":return"cancelled";default:return"running"}}statusToBadgeText(t){switch(t){case"success":return"Success";case"failure":return"Failed";case"timeout":return"Timeout";case"pending_approval":return"Pending";case"cancelled":return"Cancelled";case"interrupted":return"Interrupted";default:return t}}formatDuration(t){if(t<60)return`${t}s`;let s=Math.floor(t/60),n=t%60;return n>0?`${s}m ${n}s`:`${s}m`}formatStarted(t){try{let s=new Date(t),n=new Date;if(s.toDateString()===n.toDateString())return s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let r=new Date(n);return r.setDate(r.getDate()-1),s.toDateString()===r.toDateString()?`Yesterday ${s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`:s.toLocaleDateString([],{month:"short",day:"numeric"})+` ${s.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}`}catch{return t}}formatNextRun(t){try{let s=new Date(t),n=new Date,r=s.getTime()-n.getTime();if(r<0)return"overdue";let i=Math.round(r/6e4);if(i<60)return`${i}m`;let o=Math.round(i/60);return o<24?`${o}h`:s.toLocaleDateString([],{month:"short",day:"numeric"})}catch{return t}}getNextTaskLabel(t){let n=t.map(i=>i.nextRun).filter(Boolean).sort()[0];return n?`${t.find(i=>i.nextRun===n)?.agent??"unknown"} in ${this.formatNextRun(n)}`:"none"}getInitials(t){return t.split("-").map(s=>s[0]?.toUpperCase()??"").slice(0,2).join("")}renderAgentAvatar(t,s){let n=s.avatar?.trim();if(!n){(0,Z.setIcon)(t,"bot");return}/^[a-z][a-z0-9-]*$/.test(n)?(0,Z.setIcon)(t,n):t.setText(n)}humanizeCron(t){let s={"*/5 * * * *":"Every 5 minutes","*/10 * * * *":"Every 10 minutes","*/15 * * * *":"Every 15 minutes","*/30 * * * *":"Every 30 minutes","0 * * * *":"Every hour","0 */2 * * *":"Every 2 hours"};if(s[t])return s[t];let n=t.toLowerCase().trim();if(n.startsWith("every ")||n.startsWith("daily ")||n==="daily")return t;if(n.startsWith("hourly"))return"Every hour";if(n.startsWith("weekdays")||n.startsWith("weekly")||n.startsWith("monthly"))return t;let r=t.trim().split(/\s+/);if(r.length!==5)return t;let[i,o,l,,c]=r,d=(p,m)=>{let f=parseInt(p??"0",10),g=parseInt(m??"0",10),w=f>=12?"PM":"AM",y=f===0?12:f>12?f-12:f;return g===0?`${y} ${w}`:`${y}:${String(g).padStart(2,"0")} ${w}`},u=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],h=p=>p==="1-5"?"weekdays":p==="0,6"?"weekends":p.split(",").map(f=>parseInt(f,10)).map(f=>u[f]??f).join(", ");return o==="*"&&l==="*"&&c==="*"?i==="*"?"Every minute":`Every hour at :${String(i).padStart(2,"0")}`:l==="*"&&c==="*"&&o!=="*"?`Daily at ${d(o??"0",i??"0")}`:l==="*"&&c==="1-5"&&o!=="*"?`Weekdays at ${d(o??"0",i??"0")}`:l==="*"&&c!=="*"&&o!=="*"?`${h(c??"1")} at ${d(o??"0",i??"0")}`:c==="*"&&l!=="*"&&o!=="*"?`Monthly on the ${l} at ${d(o??"0",i??"0")}`:t}getTagClass(t){return t==="monitoring"?"monitoring":t==="devops"?"devops":t==="sample"?"sample":"default"}renderCreateAgentPage(t){let s=t.createDiv({cls:"af-create-agent-page"});sc(s,this.agentFormDeps())}renderCreateSkillPage(t){let s=t.createDiv({cls:"af-create-agent-page"});Hr(s,this.skillFormDeps())}renderEditAgentPage(t){let s=t.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"bot","No agent selected","");return}let r=this.plugin.runtime.getSnapshot().agents.find(i=>i.name===n);if(!r){this.renderEmptyState(s,"bot","Agent not found",`Agent "${n}" was not found`);return}nc(s,this.agentFormDeps(),r)}renderCreateTaskPage(t){let s=t.createDiv({cls:"af-create-agent-page"});oc(s,this.taskFormDeps())}renderEditTaskPage(t){let s=t.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"circle-dot","No task selected","");return}let r=this.plugin.runtime.getSnapshot().tasks.find(i=>i.taskId===n);if(!r){this.renderEmptyState(s,"circle-dot","Task not found",`Task "${n}" was not found`);return}lc(s,this.taskFormDeps(),r)}renderEditSkillPage(t){let s=t.createDiv({cls:"af-create-agent-page"}),n=this.detailContext;if(!n){this.renderEmptyState(s,"puzzle","No skill selected","");return}let r=this.plugin.runtime.getSnapshot().skills.find(i=>i.name===n);if(!r){this.renderEmptyState(s,"puzzle","Skill not found",`Skill "${n}" was not found`);return}Hr(s,this.skillFormDeps(),r)}renderAddMcpServerPage(t){let s=t.createDiv({cls:"af-create-agent-page"});cc(s,this.mcpFormDeps())}createFormField(t,s,n,r,i,o){let l=t.createDiv({cls:"af-form-row"}),c=l.createDiv({cls:"af-form-label"});c.setText(s),r&&this.addTooltip(c,r);let d=l.createEl("input",{cls:"af-form-input",attr:{type:"text",placeholder:n}});o!==void 0&&(d.value=o),d.addEventListener("input",()=>i(d.value))}addTooltip(t,s){let n=t.createSpan({cls:"af-form-tooltip"});(0,Z.setIcon)(n,"info"),n.createSpan({cls:"af-tooltip-text",text:s})}};function qr(a){return a>=1e6?`${(a/1e6).toFixed(1)}M`:a>=1e4?`${Math.round(a/1e3)}K`:a>=1e3?`${(a/1e3).toFixed(1)}K`:String(a)}function Rc(a){if(!a?.trim())return"not set";let e={"*/5 * * * *":"Every 5 minutes","*/10 * * * *":"Every 10 minutes","*/15 * * * *":"Every 15 minutes","*/30 * * * *":"Every 30 minutes","0 * * * *":"Every hour","0 */2 * * *":"Every 2 hours","0 */4 * * *":"Every 4 hours","0 */6 * * *":"Every 6 hours","0 */12 * * *":"Every 12 hours"};if(e[a])return e[a];let t=a.trim().split(/\s+/);if(t.length===5){let[s,n,r,,i]=t;if(r==="*"&&n&&s){let o=Number(n),l=Number(s);if(!isNaN(o)&&!isNaN(l)){let c=o>=12?"PM":"AM",u=`${o===0?12:o>12?o-12:o}:${String(l).padStart(2,"0")} ${c}`;return i==="*"?`Daily at ${u}`:i==="1-5"?`Weekdays at ${u}`:`${u} on days ${i}`}}}return a}var G=require("obsidian");function Da(a,e){return`${a}::${e}`}function Ic(){return Math.random().toString(16).slice(2,10)}function Mc(){return`New chat ${new Date().toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}`}function gp(a){let e=new Date(a).getTime();if(!Number.isFinite(e))return"";let t=Date.now()-e,s=60*1e3,n=60*s,r=24*n;return t<s?"just now":t<n?`${Math.floor(t/s)}m`:t<r?`${Math.floor(t/n)}h`:t<2*r?"yesterday":t<7*r?`${Math.floor(t/r)}d`:new Date(e).toLocaleDateString(void 0,{month:"short",day:"numeric"})}var yp=480,zr="http://www.w3.org/2000/svg";function vp(a){let e=activeDocument.createElementNS(zr,"svg");e.setAttribute("class","svg-icon af-convo-toggle-icon"),e.setAttribute("viewBox","0 0 24 24"),e.setAttribute("fill","none"),e.setAttribute("stroke","currentColor"),e.setAttribute("stroke-width","2"),e.setAttribute("stroke-linecap","round"),e.setAttribute("stroke-linejoin","round");let t=activeDocument.createElementNS(zr,"rect");for(let[n,r]of Object.entries({x:"1",y:"2",width:"22",height:"20",rx:"4"}))t.setAttribute(n,r);let s=activeDocument.createElementNS(zr,"rect");s.setAttribute("class","af-convo-toggle-bar");for(let[n,r]of Object.entries({x:"4",y:"5",width:"2",height:"14",rx:"2",fill:"currentColor"}))s.setAttribute(n,r);e.appendChild(t),e.appendChild(s),a.appendChild(e)}var Rs=class a extends G.ItemView{constructor(t,s){super(t);this.plugin=s}selectedAgentName=null;selectedConversationId="";sessions=new Map;conversationsCache=[];convoPanelEl=null;collapseBtn=null;convoPanelCollapsed=!1;userToggledCollapse=!1;resizeObserver=null;headerEl;agentSelect;messagesEl;messagesInner;textarea;sendBtn;attachStopBtn;isInStopMode=!1;attachedFiles=[];attachedImages=[];pillsRow;activityEl=null;streamingDot=null;activityUnsub=null;statsEl;statsUnsub=null;statsSourceSession=null;threadExpanded=new Map;getViewType(){return mt}getDisplayText(){if(!this.selectedAgentName)return"Agent Chat";let t=this.getCurrentConversationName();return!t||this.conversationsCache.length<=1?`Chat: ${this.selectedAgentName}`:`Chat: ${this.selectedAgentName} \xB7 ${t}`}getIcon(){return"message-circle"}getState(){return{agentName:this.selectedAgentName??null,conversationId:this.selectedConversationId,convoPanelCollapsed:this.convoPanelCollapsed}}async setState(t,s){await super.setState(t,s);let n=typeof t?.conversationId=="string"&&t.conversationId?t.conversationId:void 0;typeof t?.convoPanelCollapsed=="boolean"&&(this.convoPanelCollapsed=t.convoPanelCollapsed,this.userToggledCollapse=!0,this.applyCollapsedClass()),t?.agentName&&typeof t.agentName=="string"&&this.selectAgent(t.agentName,n)}getCurrentConversationName(){return this.conversationsCache.find(s=>s.id===this.selectedConversationId)?.name??""}async onOpen(){this.plugin.subscribeView(this),this.buildShell(),await this.render(),this.observeContainerWidth()}async onClose(){for(let{session:t}of this.sessions.values())t.abort();this.sessions.clear(),this.statsUnsub?.(),this.statsUnsub=null,this.activityUnsub?.(),this.activityUnsub=null,this.resizeObserver?.disconnect(),this.resizeObserver=null,this.plugin.unsubscribeView(this)}observeContainerWidth(){typeof ResizeObserver>"u"||(this.resizeObserver=new ResizeObserver(t=>{if(!this.userToggledCollapse)for(let s of t){let r=s.contentRect.width<yp;r!==this.convoPanelCollapsed&&(this.convoPanelCollapsed=r,this.applyCollapsedClass())}}),this.resizeObserver.observe(this.contentEl))}selectAgent(t,s){if(s){let n=this.plugin.app.workspace.getLeavesOfType(mt);for(let r of n)if(r.view!==this&&r.view instanceof a&&r.view.selectedAgentName===t&&r.view.selectedConversationId===s){this.plugin.app.workspace.revealLeaf(r);return}}this.selectedAgentName=t,s&&(this.selectedConversationId=s),this.agentSelect&&(this.agentSelect.value=t),this.leaf.updateHeader(),this.switchToAgent(t,s)}buildShell(){let t=this.contentEl;t.empty(),t.addClass("af-root");let s=t.createDiv({cls:"af-chat-view-container"});this.headerEl=s.createDiv({cls:"af-chat-view-header"}),this.collapseBtn=this.headerEl.createEl("button",{cls:"clickable-icon af-chat-convo-collapse-btn",attr:{title:"Toggle conversations panel","aria-label":"Toggle conversations panel"}}),vp(this.collapseBtn),this.collapseBtn.toggleClass("is-collapsed",this.convoPanelCollapsed),this.collapseBtn.onclick=()=>this.toggleConvoPanel(),this.agentSelect=this.headerEl.createEl("select",{cls:"af-chat-view-agent-select"});let n=this.headerEl.createEl("button",{cls:"af-btn-sm af-chat-view-new-btn"});T(n,"plus","af-btn-icon"),n.appendText(" New Chat"),n.onclick=()=>void this.handleNewChat();let r=s.createDiv({cls:"af-chat-view-body"});this.convoPanelEl=r.createDiv({cls:"af-chat-convo-panel"}),this.convoPanelCollapsed&&this.convoPanelEl.addClass("collapsed");let i=r.createDiv({cls:"af-chat-main"});this.agentSelect.onchange=()=>{let d=this.agentSelect.value;d&&(this.selectedConversationId="",this.textarea.disabled=!1,this.textarea.placeholder="Message the agent\u2026 (Shift+Enter for newline)",this.switchToAgent(d))},this.messagesEl=i.createDiv({cls:"af-chat-messages"}),this.messagesInner=this.messagesEl.createDiv({cls:"af-chat-messages-inner"});let o=i.createDiv({cls:"af-chat-input-area"});this.pillsRow=o.createDiv({cls:"af-chat-pills-row"}),this.pillsRow.setCssStyles({display:"none"});let l=o.createDiv({cls:"af-chat-input-row"});this.attachStopBtn=l.createEl("button",{cls:"af-chat-attach-btn"}),T(this.attachStopBtn,"plus","af-btn-icon"),this.attachStopBtn.title="Attach active document",this.attachStopBtn.onclick=()=>{this.isInStopMode?this.handleStop():this.attachActiveDocument()},this.textarea=l.createEl("textarea",{cls:"af-chat-input",attr:{placeholder:"Message the agent\u2026 (Shift+Enter for newline)",rows:"1"}}),this.sendBtn=l.createEl("button",{cls:"af-chat-send-btn"}),T(this.sendBtn,"arrow-up","af-btn-icon"),this.sendBtn.setCssStyles({display:"none"});let c=()=>{this.textarea.setCssStyles({height:"auto"});let d=Math.min(this.textarea.scrollHeight,160);this.textarea.setCssStyles({height:`${d}px`}),this.textarea.setCssStyles({overflowY:this.textarea.scrollHeight>160?"auto":"hidden"}),this.sendBtn.setCssStyles({display:this.textarea.value.trim()?"flex":"none"})};this.textarea.addEventListener("input",c),this.textarea.addEventListener("focus",()=>{let d=this.getCurrentSession();d&&this.setStatsSource(d.session)}),this.sendBtn.onclick=()=>void this.handleSend(),this.textarea.onkeydown=d=>{d.key==="Enter"&&!d.shiftKey&&!d.isComposing&&(d.preventDefault(),this.handleSend())},this.textarea.addEventListener("paste",d=>{let u=d.clipboardData?.items;if(u)for(let h=0;h<u.length;h++){let p=u[h];if(p.type.startsWith("image/")){d.preventDefault();let m=p.getAsFile();m&&this.attachImageBlob(m);return}}}),o.addEventListener("dragover",d=>{d.preventDefault(),d.stopPropagation(),o.addClass("af-chat-input-dragover")}),o.addEventListener("dragleave",()=>{o.removeClass("af-chat-input-dragover")}),o.addEventListener("drop",d=>{d.preventDefault(),d.stopPropagation(),o.removeClass("af-chat-input-dragover");let u=d.dataTransfer?.files;if(u)for(let h=0;h<u.length;h++){let p=u[h];p.type.startsWith("image/")&&this.attachImageBlob(p)}}),this.statsEl=o.createDiv({cls:"af-chat-stats"}),this.renderStats(null)}async render(){this.populateAgentDropdown()}setStatsSource(t){this.statsSourceSession!==t&&(this.statsUnsub?.(),this.statsSourceSession=t,this.statsUnsub=t.onStatsChange(s=>this.renderStats(s)))}renderStats(t){if(this.statsEl.empty(),!t||!t.concreteModel){this.statsEl.createSpan({cls:"af-chat-stats-muted",text:"\xA0"});return}let s=this.statsEl.createSpan({cls:"af-chat-stats-line"});if(s.createSpan({cls:"af-chat-stats-model",text:t.concreteModel}),t.contextWindow&&t.contextTokensUsed){let n=Math.min(100,Math.round(t.contextTokensUsed/t.contextWindow*100)),r=10,i=Math.min(r,Math.max(0,Math.round(n/100*r))),o="\u2593".repeat(i)+"\u2591".repeat(r-i),l=s.createSpan({cls:`af-chat-stats-ctx${n>=80?" warn":""}`});l.createSpan({cls:"af-chat-stats-bar",text:o}),l.createSpan({cls:"af-chat-stats-pct",text:`${n}%`}),l.title=`Context: ${Ds(t.contextTokensUsed)} / ${Ds(t.contextWindow)} tokens (${n}%)
|
|
12037
12024
|
|
|
12038
12025
|
Includes the agent's system prompt, attached skills, tool schemas, memory, and prior turns. A fresh chat starts non-zero because all of that is loaded on turn 1.
|
|
12039
12026
|
|
|
12040
|
-
To get 1M context on Opus, set the agent's model to claude-opus-4-7[1m] (or us.anthropic.claude-opus-4-7[1m] on Bedrock).`}if(e.lastCompact){let{preTokens:n,postTokens:a}=e.lastCompact,i=s.createSpan({cls:"af-chat-stats-compact"});i.setText(`compacted ${is(n)} \u2192 ${is(a)}`),i.title=`Conversation was summarized to free up context. ${is(n)} tokens reduced to ${is(a)}.`}}populateAgentDropdown(){let e=this.plugin.runtime.getSnapshot().agents,s=this.agentSelect.value;if(this.agentSelect.empty(),e.length===0){let a=this.agentSelect.createEl("option",{text:"No agents available",attr:{value:"",disabled:"true"}});a.selected=!0,this.textarea.disabled=!0,this.showEmptyState();return}if(!this.selectedAgentName){let a=this.agentSelect.createEl("option",{text:"Select agent\u2026",attr:{value:"",disabled:"true"}});a.selected=!0}for(let a of e){let i=a.avatar?.trim(),o=i&&!/^[a-z][a-z0-9-]*$/.test(i)?`${i} `:"";this.agentSelect.createEl("option",{text:`${o}${a.name}`,attr:{value:a.name}})}if(this.selectedAgentName&&e.some(a=>a.name===this.selectedAgentName))this.agentSelect.value=this.selectedAgentName,this.textarea.disabled=!1;else if(s&&e.some(a=>a.name===s))this.agentSelect.value=s,this.selectedAgentName=s,this.textarea.disabled=!1;else{this.selectedAgentName=null,this.leaf.updateHeader(),this.textarea.disabled=!0,this.textarea.placeholder="Select an agent to start chatting\u2026",this.showEmptyState();return}this.leaf.updateHeader(),this.textarea.placeholder="Message the agent\u2026 (Shift+Enter for newline)";let n=this.messagesInner.querySelector(".af-chat-bubble")!==null;this.selectedAgentName&&!n&&this.switchToAgent(this.selectedAgentName,this.selectedConversationId||void 0)}showEmptyState(){this.messagesInner.empty();let e=this.messagesInner.createDiv({cls:"af-chat-view-empty"}),s=e.createDiv({cls:"af-chat-view-empty-icon"});this.plugin.runtime.getSnapshot().agents.length===0?((0,z.setIcon)(s,"bot"),e.createDiv({cls:"af-chat-view-empty-text",text:"No agents available"}),e.createDiv({cls:"af-chat-view-empty-hint",text:"Create an agent to start chatting"})):((0,z.setIcon)(s,"message-circle"),e.createDiv({cls:"af-chat-view-empty-text",text:"Select an agent to start"}),e.createDiv({cls:"af-chat-view-empty-hint",text:"Choose an agent from the dropdown above"}))}async switchToAgent(e,s){let a=this.plugin.runtime.getSnapshot().agents.find(h=>h.name===e);if(!a)return;await this.loadConversations(a);let i;if(s&&this.conversationsCache.some(h=>h.id===s))i=s;else if(this.conversationsCache.length>0)i=this.conversationsCache[0].id;else{i=tl();try{await this.plugin.repository.createConversation(a,i,sl())}catch(h){new z.Notice(`Couldn't create conversation: ${h instanceof Error?h.message:String(h)}`);return}await this.loadConversations(a)}if(!s||s!==i){let h=this.plugin.app.workspace.getLeavesOfType(rt);for(let d of h)if(d.view!==this&&d.view instanceof r&&d.view.selectedAgentName===e&&d.view.selectedConversationId===i){this.plugin.app.workspace.revealLeaf(d);return}}this.selectedAgentName=e,this.selectedConversationId=i,this.leaf.updateHeader(),this.activityEl=null,this.streamingDot=null,this.messagesInner.empty(),this.threadExpanded.clear(),this.renderConvoPanel();let o=qn(e,i),c=this.sessions.get(o);if(!c){let h=new Yt(a,this.plugin.settings,this.plugin.repository,this.app.vault,{inAppConversationId:i,mcpAuth:this.plugin.mcpAuth});h.setUsageRecorder(d=>this.plugin.runtime.recordUsage(d)),c={session:h},this.sessions.set(o,c),await h.loadPersistedState()}this.setStatsSource(c.session);for(let h of c.session.messages)if(h.role==="user")this.addBubble("user",h.content,h.attachments);else{let d=this.addBubble("assistant");if(this.renderMarkdownBubble(d,h.content),d._setRawText?.(h.content),this.attachThreadAffordance(d,h.id,c.session),h.toolCalls&&h.toolCalls.length>0){let u=this.getOrCreateAffordancesRow(d);this.buildToolSummary(h.toolCalls,u)}}this.activityUnsub?.();let l=c.session;this.activityUnsub=l.onActivityChange(()=>{this.getCurrentSession()?.session===l&&this.renderIndicators(l)}),this.textarea.disabled=!1,this.textarea.focus()}getCurrentSession(){if(this.selectedAgentName)return this.sessions.get(qn(this.selectedAgentName,this.selectedConversationId))}async loadConversations(e){this.conversationsCache=await this.plugin.repository.listConversations(e)}async refreshConversationsList(e){await this.loadConversations(e),this.renderConvoPanel(),this.leaf.updateHeader()}renderConvoPanel(){if(!this.convoPanelEl||(this.convoPanelEl.empty(),!this.selectedAgentName))return;this.convoPanelEl.createDiv({cls:"af-chat-convo-header",text:"Conversations"});let e=this.convoPanelEl.createDiv({cls:"af-chat-convo-new"}),s=e.createSpan({cls:"af-chat-convo-new-icon"});(0,z.setIcon)(s,"plus"),e.createSpan({cls:"af-chat-convo-new-label",text:"New chat"}),e.onclick=()=>void this.handleNewChat();let n=this.convoPanelEl.createDiv({cls:"af-chat-convo-list"});for(let a of this.conversationsCache)this.renderConvoRow(n,a)}renderConvoRow(e,s){let n=s.id===this.selectedConversationId,a=e.createDiv({cls:`af-chat-convo-item${n?" active":""}`}),i=a.createDiv({cls:"af-chat-convo-name",text:s.name});i.title=s.name,i.ondblclick=h=>{h.stopPropagation(),this.beginInlineRename(i,s)};let o=a.createDiv({cls:"af-chat-convo-meta"}),c=s.messageCount===1?"1 msg":`${s.messageCount} msgs`;o.appendText(`${c} \xB7 ${Ch(s.lastActive)}`);let l=a.createEl("button",{cls:"af-chat-convo-trash",attr:{title:"Delete conversation","aria-label":"Delete conversation"}});(0,z.setIcon)(l,"trash-2"),l.onclick=h=>{h.stopPropagation(),this.handleDeleteConversation(s)},a.onclick=()=>{s.id!==this.selectedConversationId&&this.handleConvoSelected(s.id)}}beginInlineRename(e,s){let n=s.name,a=activeDocument.createElement("input");a.type="text",a.value=n,a.className="af-chat-convo-name-input",e.replaceWith(a),a.focus(),a.select();let i=!1,o=l=>{let h=activeDocument.createElement("div");return h.className="af-chat-convo-name",h.textContent=l??n,h.title=l??n,h.ondblclick=d=>{d.stopPropagation();let u=this.conversationsCache.find(p=>p.id===s.id)??s;this.beginInlineRename(h,u)},a.replaceWith(h),h},c=async()=>{if(i)return;i=!0;let l=a.value.trim();if(!l||l===n){o(null);return}try{await this.saveConversationName(s.id,l)}catch(h){new z.Notice(`Couldn't rename: ${h instanceof Error?h.message:String(h)}`),o(null);return}this.renderConvoPanel(),this.leaf.updateHeader()};a.addEventListener("keydown",l=>{l.key==="Enter"?(l.preventDefault(),c()):l.key==="Escape"&&(l.preventDefault(),i=!0,o(null))}),a.addEventListener("blur",()=>{c()})}async saveConversationName(e,s){if(!this.selectedAgentName)return;let a=this.plugin.runtime.getSnapshot().agents.find(l=>l.name===this.selectedAgentName);if(!a)return;try{await this.plugin.repository.renameConversation(a,e,s)}catch{}let i=qn(this.selectedAgentName,e),o=this.sessions.get(i);o&&await o.session.setConversationName(s);let c=this.conversationsCache.findIndex(l=>l.id===e);c>=0&&(this.conversationsCache[c]={...this.conversationsCache[c],name:s})}async handleConvoSelected(e){if(!this.selectedAgentName)return;let s=this.plugin.app.workspace.getLeavesOfType(rt);for(let n of s)if(n.view!==this&&n.view instanceof r&&n.view.selectedAgentName===this.selectedAgentName&&n.view.selectedConversationId===e){this.plugin.app.workspace.revealLeaf(n);return}await this.switchToAgent(this.selectedAgentName,e)}handleDeleteConversation(e){let s=this.selectedAgentName;if(!s)return;let a=this.plugin.runtime.getSnapshot().agents.find(i=>i.name===s);a&&new qt(this.app,{title:`Delete conversation "${e.name}"?`,body:"This removes its message history. The agent and its other conversations are untouched.",confirmText:"Delete",danger:!0,onConfirm:async()=>{let i=qn(s,e.id);this.sessions.get(i)?.session.dispose(),this.sessions.delete(i);try{await this.plugin.repository.deleteConversation(a,e.id)}catch(o){new z.Notice(`Couldn't delete: ${o instanceof Error?o.message:String(o)}`);return}if(await this.refreshConversationsList(a),e.id===this.selectedConversationId){let o=this.conversationsCache[0]?.id;await this.switchToAgent(s,o)}}}).open()}toggleConvoPanel(){this.convoPanelCollapsed=!this.convoPanelCollapsed,this.userToggledCollapse=!0,this.applyCollapsedClass(),this.leaf.updateHeader()}applyCollapsedClass(){this.convoPanelEl&&(this.convoPanelCollapsed?this.convoPanelEl.addClass("collapsed"):this.convoPanelEl.removeClass("collapsed")),this.collapseBtn&&this.collapseBtn.toggleClass("is-collapsed",this.convoPanelCollapsed)}renderMarkdownBubble(e,s){let n=e.querySelector(".af-chat-copy-btn"),a=n?.parentNode?.removeChild(n)??null;e.empty(),e.addClass("af-compact-md"),z.MarkdownRenderer.render(this.app,s,e,"",this).then(()=>{a&&e.appendChild(a),this.wireBubbleLinks(e),e.querySelectorAll("pre").forEach(i=>{i.querySelector(".copy-code-button")?.remove();let o=i.querySelector("code");if(!o)return;let c=activeDocument.createElement("button");c.className="af-code-copy-btn",c.setAttribute("aria-label","Copy code"),(0,z.setIcon)(c,"copy"),c.onclick=l=>{l.stopPropagation(),navigator.clipboard.writeText(o.textContent??"").then(()=>{c.addClass("copied"),(0,z.setIcon)(c,"check"),window.setTimeout(()=>{c.removeClass("copied"),(0,z.setIcon)(c,"copy")},1500)})},i.setCssStyles({position:"relative"}),i.appendChild(c)})})}wireBubbleLinks(e){e.addEventListener("click",s=>{let n=s.target.closest("a");if(!n)return;if(n.classList.contains("internal-link")){s.preventDefault(),s.stopPropagation();let i=n.getAttribute("data-href")||n.getAttribute("href")||n.textContent||"";if(!i)return;let o=s.shiftKey?"split":"tab";this.app.workspace.openLinkText(i,"",o);return}let a=n.getAttribute("href")||"";if(a.startsWith("obsidian://")){s.preventDefault(),s.stopPropagation(),window.location.href=a;return}if(n.classList.contains("external-link")||/^https?:\/\//.test(a)){s.preventDefault(),s.stopPropagation(),window.open(a,"_blank");return}})}addCopyBtn(e,s){let n=e.createEl("button",{cls:"af-chat-copy-btn",attr:{"aria-label":"Copy message"}});(0,z.setIcon)(n,"copy"),n.onclick=a=>{a.stopPropagation(),navigator.clipboard.writeText(s()).then(()=>{n.addClass("copied"),(0,z.setIcon)(n,"check"),window.setTimeout(()=>{n.removeClass("copied"),(0,z.setIcon)(n,"copy")},1500)})}}addBubble(e,s,n){if(e==="user"&&n&&n.length>0){let i=this.messagesInner.createDiv({cls:"af-chat-bubble-attachments"});for(let o of n){let c=i.createSpan({cls:"af-chat-pill af-chat-pill-inline"}),l=c.createSpan({cls:"af-chat-pill-icon"}),h=/\.(png|jpe?g|gif|webp|svg|bmp)$/i.test(o);(0,z.setIcon)(l,h?"image":"file-text"),c.createSpan({cls:"af-chat-pill-name",text:o})}}let a=this.messagesInner.createDiv({cls:`af-chat-bubble af-chat-bubble-${e}`});if(s&&(e==="assistant"?this.renderMarkdownBubble(a,s):a.setText(s)),e==="assistant"){let i=s??"";this.addCopyBtn(a,()=>i),a._setRawText=o=>{i=o}}return this.messagesEl.scrollTop=this.messagesEl.scrollHeight,a}getOrCreateAffordancesRow(e){let s=e.parentElement;if(!s)throw new Error("bubble has no parent");let n=e.nextElementSibling;if(n&&n.classList.contains("af-chat-affordances"))return n;let a=activeDocument.createElement("div");return a.className="af-chat-affordances",s.insertBefore(a,e.nextSibling),a}attachThreadAffordance(e,s,n){let a=e.parentElement;if(!a)return;let i=this.getOrCreateAffordancesRow(e);if(i.querySelector(".af-thread-badge"))return;let o=activeDocument.createElement("div");o.className="af-thread-badge",o.setAttribute("role","button"),o.setAttribute("tabindex","0"),i.appendChild(o),(0,z.setIcon)(o,"message-circle");let c=o.createSpan({cls:"af-thread-badge-label"}),l=activeDocument.createElement("div");l.className="af-thread-container",l.setCssStyles({display:"none"}),a.insertBefore(l,i.nextSibling);let h=()=>{let f=n.getThreadIndex()[s]?.messageCount??0;f<=0?c.setText("Thread"):c.setText(`${f} ${f===1?"reply":"replies"}`),f>0&&o.addClass("has-replies")};h();let d=!1,u=async()=>{if(this.threadExpanded.get(s)===!0){l.setCssStyles({display:"none"}),this.threadExpanded.set(s,!1),o.removeClass("expanded"),this.setStatsSource(n);return}if(this.threadExpanded.set(s,!0),l.setCssStyles({display:""}),o.addClass("expanded"),!d)try{let m=await n.openOrCreateThread(s);this.renderThreadContainer(l,m,n,h),d=!0}catch(m){l.setText(`Failed to open thread: ${m instanceof Error?m.message:String(m)}`)}};o.onclick=()=>void u(),o.onkeydown=p=>{(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),u())}}renderThreadContainer(e,s,n,a){e.empty();let i=e.createDiv({cls:"af-thread-wrap"}),o=i.createDiv({cls:"af-thread-messages"}),c=null,l=null,h=C=>{C?(c||(c=o.createDiv({cls:"af-chat-activity"})),c.setText(`Working\u2026 (${C})`)):c&&(c.remove(),c=null)},d=C=>{if(C&&!l){l=o.createDiv({cls:"af-chat-streaming-dot"});for(let E=0;E<3;E++)l.createSpan()}else!C&&l&&(l.remove(),l=null)},u=(C,E,P)=>{if(C==="user"&&P&&P.length>0){let M=o.createDiv({cls:"af-chat-bubble-attachments"});for(let U of P){let $=M.createSpan({cls:"af-chat-pill af-chat-pill-inline"}),Z=$.createSpan({cls:"af-chat-pill-icon"});(0,z.setIcon)(Z,U.match(/\.(png|jpe?g|gif|webp|svg)$/i)?"image":"file-text"),$.createSpan({cls:"af-chat-pill-name",text:U})}}let N=o.createDiv({cls:`af-thread-bubble af-thread-bubble-${C}`});return C==="assistant"?this.renderMarkdownBubble(N,E):N.setText(E),N};for(let C of s.messages)u(C.role,C.content,C.attachments);let p=[],m=[],f=i.createDiv({cls:"af-thread-composer-wrap"}),g=f.createDiv({cls:"af-chat-pills-row af-thread-pills-row"});g.setCssStyles({display:"none"});let y=()=>{if(g.empty(),p.length===0&&m.length===0){g.setCssStyles({display:"none"});return}g.setCssStyles({display:"flex"});for(let C of p){let E=g.createDiv({cls:"af-chat-pill"}),P=E.createSpan({cls:"af-chat-pill-icon"});(0,z.setIcon)(P,"file-text"),E.createSpan({cls:"af-chat-pill-name",text:C.name});let N=E.createSpan({cls:"af-chat-pill-remove"});(0,z.setIcon)(N,"x"),N.onclick=M=>{M.stopPropagation();let U=p.findIndex($=>$.path===C.path);U>=0&&p.splice(U,1),y()}}for(let C of m){let E=g.createDiv({cls:"af-chat-pill"}),P=E.createSpan({cls:"af-chat-pill-icon"});(0,z.setIcon)(P,"image"),E.createSpan({cls:"af-chat-pill-name",text:C.name});let N=E.createSpan({cls:"af-chat-pill-remove"});(0,z.setIcon)(N,"x"),N.onclick=M=>{M.stopPropagation();let U=m.findIndex($=>$.path===C.path);U>=0&&m.splice(U,1),y()}}},v=()=>{let C=this.app.workspace.getActiveFile();if(!C){new z.Notice("No active document to attach");return}if(p.some(P=>P.path===C.path)){new z.Notice(`"${C.name}" is already attached`);return}if(!new Set(["md","txt","json","yaml","yml","toml","csv","xml","html","css","js","ts","py","sh","sql","env","cfg","ini","log"]).has(C.extension.toLowerCase())){new z.Notice(`Can't attach "${C.name}" \u2014 only text files are supported`);return}p.push(C),y()},k=async C=>{let E=C.type.split("/")[1]?.replace("jpeg","jpg")??"png",P=C.name&&C.name!=="image"?C.name:`pasted-${Date.now()}.${E}`;if(m.some(M=>M.name===P)){new z.Notice(`"${P}" is already attached`);return}let N=await this.saveImageBlobToVault(C);N&&(m.push(N),y())},w=f.createDiv({cls:"af-chat-input-row af-thread-composer"}),S=w.createEl("button",{cls:"af-chat-attach-btn"});R(S,"plus","af-btn-icon"),S.title="Attach active document",S.onclick=C=>{C.preventDefault(),v()};let T=w.createEl("textarea",{cls:"af-chat-input af-thread-input",attr:{placeholder:"Message in thread\u2026 (Shift+Enter for newline)",rows:"1"}});T.addEventListener("paste",C=>{let E=C.clipboardData?.items;if(E)for(let P=0;P<E.length;P++){let N=E[P];if(N.type.startsWith("image/")){C.preventDefault();let M=N.getAsFile();M&&k(M);return}}}),f.addEventListener("dragover",C=>{C.preventDefault(),C.stopPropagation(),f.addClass("af-chat-input-dragover")}),f.addEventListener("dragleave",()=>{f.removeClass("af-chat-input-dragover")}),f.addEventListener("drop",C=>{C.preventDefault(),C.stopPropagation(),f.removeClass("af-chat-input-dragover");let E=C.dataTransfer?.files;if(E)for(let P=0;P<E.length;P++){let N=E[P];N.type.startsWith("image/")&&k(N)}});let _=w.createEl("button",{cls:"af-chat-send-btn"});R(_,"arrow-up","af-btn-icon"),_.setCssStyles({display:"none"});let D=()=>{T.setCssStyles({height:"auto"}),T.setCssStyles({height:`${Math.min(T.scrollHeight,120)}px`}),_.setCssStyles({display:T.value.trim()?"flex":"none"})};T.addEventListener("input",D),T.addEventListener("focus",()=>this.setStatsSource(s));let O=async()=>{let C=T.value.trim();if(!C||s.isStreaming)return;let E=await this.buildAttachmentContextFor(p,m),P=[...p.map($=>$.name),...m.map($=>$.name)],N=E?`${E}${C}`:void 0;T.value="",D(),p.length=0,m.length=0,y(),u("user",C,P.length>0?P:void 0),d(!0);let M=null,U="";try{await s.sendMessage(C,$=>{if($.type==="text"){M||(d(!1),h(),M=u("assistant",""),M.empty()),U+=$.content;let Z=M.querySelector(".af-chat-stream-text");Z||(Z=M.createDiv({cls:"af-chat-stream-text"})),Z.setText(U)}else $.type==="tool_use"?h($.toolName):$.type==="result"&&(h(),d(!1),M&&this.renderMarkdownBubble(M,At(U)))},N,P.length>0?P:void 0),a()}catch($){d(!1),h();let Z=$ instanceof Error?$.message:String($);o.createDiv({cls:"af-thread-error",text:`Error: ${Z}`})}};_.onclick=()=>void O(),T.onkeydown=C=>{C.key==="Enter"&&!C.shiftKey&&!C.isComposing&&(C.preventDefault(),O())}}buildToolSummary(e,s){let a=(s??this.messagesInner).createDiv({cls:"af-chat-tool-summary"}),i=a.createEl("details"),o=i.createEl("summary"),c=new Map;for(let d of e){let u=c.get(d.name)??[];d.command&&u.push(d.command),c.set(d.name,u)}let l=o.createSpan({cls:"af-chat-tool-icon"});(0,z.setIcon)(l,"wrench"),o.appendText(` ${e.length} tool call${e.length!==1?"s":""}`);let h=i.createDiv({cls:"af-chat-tool-list"});for(let[d,u]of c){let p=u.length||(c.get(d)?.length??1),m=h.createDiv({cls:"af-chat-tool-item"}),f=p>1?`${d} (\xD7${p})`:d;m.createSpan({cls:"af-chat-tool-name",text:f}),u.length===1&&u[0]&&m.createSpan({cls:"af-chat-tool-cmd",text:u[0]})}return a}renderIndicators(e){let s=e.isStreaming,n=e.currentToolName,a=e.hasCurrentTurnText,i=!!this.messagesInner.querySelector(".af-chat-stream-text"),o=null;if(s&&n?o=`Working\u2026 (${n})`:s&&a&&!i&&(o="Replying\u2026"),o?(this.activityEl?(this.activityEl.parentElement!==this.messagesInner||this.activityEl.nextElementSibling!==null)&&this.messagesInner.appendChild(this.activityEl):this.activityEl=this.messagesInner.createDiv({cls:"af-chat-activity"}),this.activityEl.textContent!==o&&this.activityEl.setText(o)):this.activityEl&&(this.activityEl.remove(),this.activityEl=null),s&&!n&&!a)if(this.streamingDot)(this.streamingDot.parentElement!==this.messagesInner||this.streamingDot.nextElementSibling!==null)&&this.messagesInner.appendChild(this.streamingDot);else{this.streamingDot=this.messagesInner.createDiv({cls:"af-chat-streaming-dot"});for(let l=0;l<3;l++)this.streamingDot.createSpan()}else this.streamingDot&&(this.streamingDot.remove(),this.streamingDot=null);this.setAttachStopMode(s)}setAttachStopMode(e){e!==this.isInStopMode&&(this.isInStopMode=e,this.attachStopBtn.empty(),e?(R(this.attachStopBtn,"square","af-btn-icon"),this.attachStopBtn.title="Stop generation",this.attachStopBtn.addClass("af-chat-stop-mode")):(R(this.attachStopBtn,"plus","af-btn-icon"),this.attachStopBtn.title="Attach active document",this.attachStopBtn.removeClass("af-chat-stop-mode")))}handleStop(){let e=this.getCurrentSession();e&&(e.session.abort(),this.addBubble("error","Generation stopped"))}attachActiveDocument(){let e=this.app.workspace.getActiveFile();if(!e){new z.Notice("No active document to attach");return}if(this.attachedFiles.some(a=>a.path===e.path)){new z.Notice(`"${e.name}" is already attached`);return}let s=e.extension.toLowerCase();if(!new Set(["md","txt","json","yaml","yml","toml","csv","xml","html","css","js","ts","py","sh","sql","env","cfg","ini","log"]).has(s)){new z.Notice(`Can't attach "${e.name}" \u2014 only text files are supported`);return}this.attachedFiles.push(e),this.renderPills()}async saveImageBlobToVault(e){let s=e.type.split("/")[1]?.replace("jpeg","jpg")??"png",n=Date.now(),a=e.name&&e.name!=="image"?e.name:`pasted-${n}.${s}`,i=`${this.plugin.settings.fleetFolder}/chat-images`,o=`${i}/${n}-${a}`;try{this.app.vault.getAbstractFileByPath(i)||await this.app.vault.createFolder(i);let c=await e.arrayBuffer();await this.app.vault.createBinary(o,c);let h=this.app.vault.adapter.getBasePath?.()??"";return{name:a,path:`${h}/${o}`}}catch(c){let l=c instanceof Error?c.message:String(c);return new z.Notice(`Failed to save image: ${l}`),null}}async buildAttachmentContextFor(e,s){if(e.length===0&&s.length===0)return"";let n=[];for(let a of e)try{let i=await this.app.vault.cachedRead(a);n.push(`### ${a.name}
|
|
12027
|
+
To get 1M context on Opus, set the agent's model to claude-opus-4-7[1m] (or us.anthropic.claude-opus-4-7[1m] on Bedrock).`}if(t.lastCompact){let{preTokens:n,postTokens:r}=t.lastCompact,i=s.createSpan({cls:"af-chat-stats-compact"});i.setText(`compacted ${Ds(n)} \u2192 ${Ds(r)}`),i.title=`Conversation was summarized to free up context. ${Ds(n)} tokens reduced to ${Ds(r)}.`}}populateAgentDropdown(){let t=this.plugin.runtime.getSnapshot().agents,s=this.agentSelect.value;if(this.agentSelect.empty(),t.length===0){let r=this.agentSelect.createEl("option",{text:"No agents available",attr:{value:"",disabled:"true"}});r.selected=!0,this.textarea.disabled=!0,this.showEmptyState();return}if(!this.selectedAgentName){let r=this.agentSelect.createEl("option",{text:"Select agent\u2026",attr:{value:"",disabled:"true"}});r.selected=!0}for(let r of t){let i=r.avatar?.trim(),o=i&&!/^[a-z][a-z0-9-]*$/.test(i)?`${i} `:"";this.agentSelect.createEl("option",{text:`${o}${r.name}`,attr:{value:r.name}})}if(this.selectedAgentName&&t.some(r=>r.name===this.selectedAgentName))this.agentSelect.value=this.selectedAgentName,this.textarea.disabled=!1;else if(s&&t.some(r=>r.name===s))this.agentSelect.value=s,this.selectedAgentName=s,this.textarea.disabled=!1;else{this.selectedAgentName=null,this.leaf.updateHeader(),this.textarea.disabled=!0,this.textarea.placeholder="Select an agent to start chatting\u2026",this.showEmptyState();return}this.leaf.updateHeader(),this.textarea.placeholder="Message the agent\u2026 (Shift+Enter for newline)";let n=this.messagesInner.querySelector(".af-chat-bubble")!==null;this.selectedAgentName&&!n&&this.switchToAgent(this.selectedAgentName,this.selectedConversationId||void 0)}showEmptyState(){this.messagesInner.empty();let t=this.messagesInner.createDiv({cls:"af-chat-view-empty"}),s=t.createDiv({cls:"af-chat-view-empty-icon"});this.plugin.runtime.getSnapshot().agents.length===0?((0,G.setIcon)(s,"bot"),t.createDiv({cls:"af-chat-view-empty-text",text:"No agents available"}),t.createDiv({cls:"af-chat-view-empty-hint",text:"Create an agent to start chatting"})):((0,G.setIcon)(s,"message-circle"),t.createDiv({cls:"af-chat-view-empty-text",text:"Select an agent to start"}),t.createDiv({cls:"af-chat-view-empty-hint",text:"Choose an agent from the dropdown above"}))}async switchToAgent(t,s){let r=this.plugin.runtime.getSnapshot().agents.find(d=>d.name===t);if(!r)return;await this.loadConversations(r);let i;if(s&&this.conversationsCache.some(d=>d.id===s))i=s;else if(this.conversationsCache.length>0)i=this.conversationsCache[0].id;else{i=Ic();try{await this.plugin.repository.createConversation(r,i,Mc())}catch(d){new G.Notice(`Couldn't create conversation: ${d instanceof Error?d.message:String(d)}`);return}await this.loadConversations(r)}if(!s||s!==i){let d=this.plugin.app.workspace.getLeavesOfType(mt);for(let u of d)if(u.view!==this&&u.view instanceof a&&u.view.selectedAgentName===t&&u.view.selectedConversationId===i){this.plugin.app.workspace.revealLeaf(u);return}}this.selectedAgentName=t,this.selectedConversationId=i,this.leaf.updateHeader(),this.activityEl=null,this.streamingDot=null,this.messagesInner.empty(),this.threadExpanded.clear(),this.renderConvoPanel();let o=Da(t,i),l=this.sessions.get(o);if(!l){let d=new ys(r,this.plugin.settings,this.plugin.repository,this.app.vault,{inAppConversationId:i,mcpAuth:this.plugin.mcpAuth});d.setUsageRecorder(u=>this.plugin.runtime.recordUsage(u)),l={session:d},this.sessions.set(o,l),await d.loadPersistedState()}this.setStatsSource(l.session);for(let d of l.session.messages)if(d.role==="user")this.addBubble("user",d.content,d.attachments);else{let u=this.addBubble("assistant");if(this.renderMarkdownBubble(u,d.content),u._setRawText?.(d.content),this.attachThreadAffordance(u,d.id,l.session),d.toolCalls&&d.toolCalls.length>0){let h=this.getOrCreateAffordancesRow(u);this.buildToolSummary(d.toolCalls,h)}}this.activityUnsub?.();let c=l.session;this.activityUnsub=c.onActivityChange(()=>{this.getCurrentSession()?.session===c&&this.renderIndicators(c)}),this.textarea.disabled=!1,this.textarea.focus()}getCurrentSession(){if(this.selectedAgentName)return this.sessions.get(Da(this.selectedAgentName,this.selectedConversationId))}async loadConversations(t){this.conversationsCache=await this.plugin.repository.listConversations(t)}async refreshConversationsList(t){await this.loadConversations(t),this.renderConvoPanel(),this.leaf.updateHeader()}renderConvoPanel(){if(!this.convoPanelEl||(this.convoPanelEl.empty(),!this.selectedAgentName))return;this.convoPanelEl.createDiv({cls:"af-chat-convo-header",text:"Conversations"});let t=this.convoPanelEl.createDiv({cls:"af-chat-convo-new"}),s=t.createSpan({cls:"af-chat-convo-new-icon"});(0,G.setIcon)(s,"plus"),t.createSpan({cls:"af-chat-convo-new-label",text:"New chat"}),t.onclick=()=>void this.handleNewChat();let n=this.convoPanelEl.createDiv({cls:"af-chat-convo-list"});for(let r of this.conversationsCache)this.renderConvoRow(n,r)}renderConvoRow(t,s){let n=s.id===this.selectedConversationId,r=t.createDiv({cls:`af-chat-convo-item${n?" active":""}`}),i=r.createDiv({cls:"af-chat-convo-name",text:s.name});i.title=s.name,i.ondblclick=d=>{d.stopPropagation(),this.beginInlineRename(i,s)};let o=r.createDiv({cls:"af-chat-convo-meta"}),l=s.messageCount===1?"1 msg":`${s.messageCount} msgs`;o.appendText(`${l} \xB7 ${gp(s.lastActive)}`);let c=r.createEl("button",{cls:"af-chat-convo-trash",attr:{title:"Delete conversation","aria-label":"Delete conversation"}});(0,G.setIcon)(c,"trash-2"),c.onclick=d=>{d.stopPropagation(),this.handleDeleteConversation(s)},r.onclick=()=>{s.id!==this.selectedConversationId&&this.handleConvoSelected(s.id)}}beginInlineRename(t,s){let n=s.name,r=activeDocument.createElement("input");r.type="text",r.value=n,r.className="af-chat-convo-name-input",t.replaceWith(r),r.focus(),r.select();let i=!1,o=c=>{let d=activeDocument.createElement("div");return d.className="af-chat-convo-name",d.textContent=c??n,d.title=c??n,d.ondblclick=u=>{u.stopPropagation();let h=this.conversationsCache.find(p=>p.id===s.id)??s;this.beginInlineRename(d,h)},r.replaceWith(d),d},l=async()=>{if(i)return;i=!0;let c=r.value.trim();if(!c||c===n){o(null);return}try{await this.saveConversationName(s.id,c)}catch(d){new G.Notice(`Couldn't rename: ${d instanceof Error?d.message:String(d)}`),o(null);return}this.renderConvoPanel(),this.leaf.updateHeader()};r.addEventListener("keydown",c=>{c.key==="Enter"?(c.preventDefault(),l()):c.key==="Escape"&&(c.preventDefault(),i=!0,o(null))}),r.addEventListener("blur",()=>{l()})}async saveConversationName(t,s){if(!this.selectedAgentName)return;let r=this.plugin.runtime.getSnapshot().agents.find(c=>c.name===this.selectedAgentName);if(!r)return;try{await this.plugin.repository.renameConversation(r,t,s)}catch{}let i=Da(this.selectedAgentName,t),o=this.sessions.get(i);o&&await o.session.setConversationName(s);let l=this.conversationsCache.findIndex(c=>c.id===t);l>=0&&(this.conversationsCache[l]={...this.conversationsCache[l],name:s})}async handleConvoSelected(t){if(!this.selectedAgentName)return;let s=this.plugin.app.workspace.getLeavesOfType(mt);for(let n of s)if(n.view!==this&&n.view instanceof a&&n.view.selectedAgentName===this.selectedAgentName&&n.view.selectedConversationId===t){this.plugin.app.workspace.revealLeaf(n);return}await this.switchToAgent(this.selectedAgentName,t)}handleDeleteConversation(t){let s=this.selectedAgentName;if(!s)return;let r=this.plugin.runtime.getSnapshot().agents.find(i=>i.name===s);r&&new ut(this.app,{title:`Delete conversation "${t.name}"?`,body:"This removes its message history. The agent and its other conversations are untouched.",confirmText:"Delete",danger:!0,onConfirm:async()=>{let i=Da(s,t.id);this.sessions.get(i)?.session.dispose(),this.sessions.delete(i);try{await this.plugin.repository.deleteConversation(r,t.id)}catch(o){new G.Notice(`Couldn't delete: ${o instanceof Error?o.message:String(o)}`);return}if(await this.refreshConversationsList(r),t.id===this.selectedConversationId){let o=this.conversationsCache[0]?.id;await this.switchToAgent(s,o)}}}).open()}toggleConvoPanel(){this.convoPanelCollapsed=!this.convoPanelCollapsed,this.userToggledCollapse=!0,this.applyCollapsedClass(),this.leaf.updateHeader()}applyCollapsedClass(){this.convoPanelEl&&(this.convoPanelCollapsed?this.convoPanelEl.addClass("collapsed"):this.convoPanelEl.removeClass("collapsed")),this.collapseBtn&&this.collapseBtn.toggleClass("is-collapsed",this.convoPanelCollapsed)}renderMarkdownBubble(t,s){let n=t.querySelector(".af-chat-copy-btn"),r=n?.parentNode?.removeChild(n)??null;t.empty(),t.addClass("af-compact-md"),G.MarkdownRenderer.render(this.app,s,t,"",this).then(()=>{r&&t.appendChild(r),this.wireBubbleLinks(t),t.querySelectorAll("pre").forEach(i=>{i.querySelector(".copy-code-button")?.remove();let o=i.querySelector("code");if(!o)return;let l=activeDocument.createElement("button");l.className="af-code-copy-btn",l.setAttribute("aria-label","Copy code"),(0,G.setIcon)(l,"copy"),l.onclick=c=>{c.stopPropagation(),navigator.clipboard.writeText(o.textContent??"").then(()=>{l.addClass("copied"),(0,G.setIcon)(l,"check"),window.setTimeout(()=>{l.removeClass("copied"),(0,G.setIcon)(l,"copy")},1500)})},i.setCssStyles({position:"relative"}),i.appendChild(l)})})}wireBubbleLinks(t){t.addEventListener("click",s=>{let n=s.target.closest("a");if(!n)return;if(n.classList.contains("internal-link")){s.preventDefault(),s.stopPropagation();let i=n.getAttribute("data-href")||n.getAttribute("href")||n.textContent||"";if(!i)return;let o=s.shiftKey?"split":"tab";this.app.workspace.openLinkText(i,"",o);return}let r=n.getAttribute("href")||"";if(r.startsWith("obsidian://")){s.preventDefault(),s.stopPropagation(),window.location.href=r;return}if(n.classList.contains("external-link")||/^https?:\/\//.test(r)){s.preventDefault(),s.stopPropagation(),window.open(r,"_blank");return}})}addCopyBtn(t,s){let n=t.createEl("button",{cls:"af-chat-copy-btn",attr:{"aria-label":"Copy message"}});(0,G.setIcon)(n,"copy"),n.onclick=r=>{r.stopPropagation(),navigator.clipboard.writeText(s()).then(()=>{n.addClass("copied"),(0,G.setIcon)(n,"check"),window.setTimeout(()=>{n.removeClass("copied"),(0,G.setIcon)(n,"copy")},1500)})}}addBubble(t,s,n){if(t==="user"&&n&&n.length>0){let i=this.messagesInner.createDiv({cls:"af-chat-bubble-attachments"});for(let o of n){let l=i.createSpan({cls:"af-chat-pill af-chat-pill-inline"}),c=l.createSpan({cls:"af-chat-pill-icon"}),d=/\.(png|jpe?g|gif|webp|svg|bmp)$/i.test(o);(0,G.setIcon)(c,d?"image":"file-text"),l.createSpan({cls:"af-chat-pill-name",text:o})}}let r=this.messagesInner.createDiv({cls:`af-chat-bubble af-chat-bubble-${t}`});if(s&&(t==="assistant"?this.renderMarkdownBubble(r,s):r.setText(s)),t==="assistant"){let i=s??"";this.addCopyBtn(r,()=>i),r._setRawText=o=>{i=o}}return this.messagesEl.scrollTop=this.messagesEl.scrollHeight,r}getOrCreateAffordancesRow(t){let s=t.parentElement;if(!s)throw new Error("bubble has no parent");let n=t.nextElementSibling;if(n&&n.classList.contains("af-chat-affordances"))return n;let r=activeDocument.createElement("div");return r.className="af-chat-affordances",s.insertBefore(r,t.nextSibling),r}attachThreadAffordance(t,s,n){let r=t.parentElement;if(!r)return;let i=this.getOrCreateAffordancesRow(t);if(i.querySelector(".af-thread-badge"))return;let o=activeDocument.createElement("div");o.className="af-thread-badge",o.setAttribute("role","button"),o.setAttribute("tabindex","0"),i.appendChild(o),(0,G.setIcon)(o,"message-circle");let l=o.createSpan({cls:"af-thread-badge-label"}),c=activeDocument.createElement("div");c.className="af-thread-container",c.setCssStyles({display:"none"}),r.insertBefore(c,i.nextSibling);let d=()=>{let f=n.getThreadIndex()[s]?.messageCount??0;f<=0?l.setText("Thread"):l.setText(`${f} ${f===1?"reply":"replies"}`),f>0&&o.addClass("has-replies")};d();let u=!1,h=async()=>{if(this.threadExpanded.get(s)===!0){c.setCssStyles({display:"none"}),this.threadExpanded.set(s,!1),o.removeClass("expanded"),this.setStatsSource(n);return}if(this.threadExpanded.set(s,!0),c.setCssStyles({display:""}),o.addClass("expanded"),!u)try{let m=await n.openOrCreateThread(s);this.renderThreadContainer(c,m,n,d),u=!0}catch(m){c.setText(`Failed to open thread: ${m instanceof Error?m.message:String(m)}`)}};o.onclick=()=>void h(),o.onkeydown=p=>{(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),h())}}renderThreadContainer(t,s,n,r){t.empty();let i=t.createDiv({cls:"af-thread-wrap"}),o=i.createDiv({cls:"af-thread-messages"}),l=null,c=null,d=x=>{x?(l||(l=o.createDiv({cls:"af-chat-activity"})),l.setText(`Working\u2026 (${x})`)):l&&(l.remove(),l=null)},u=x=>{if(x&&!c){c=o.createDiv({cls:"af-chat-streaming-dot"});for(let _=0;_<3;_++)c.createSpan()}else!x&&c&&(c.remove(),c=null)},h=(x,_,R)=>{if(x==="user"&&R&&R.length>0){let F=o.createDiv({cls:"af-chat-bubble-attachments"});for(let B of R){let q=F.createSpan({cls:"af-chat-pill af-chat-pill-inline"}),oe=q.createSpan({cls:"af-chat-pill-icon"});(0,G.setIcon)(oe,B.match(/\.(png|jpe?g|gif|webp|svg)$/i)?"image":"file-text"),q.createSpan({cls:"af-chat-pill-name",text:B})}}let O=o.createDiv({cls:`af-thread-bubble af-thread-bubble-${x}`});return x==="assistant"?this.renderMarkdownBubble(O,_):O.setText(_),O};for(let x of s.messages)h(x.role,x.content,x.attachments);let p=[],m=[],f=i.createDiv({cls:"af-thread-composer-wrap"}),g=f.createDiv({cls:"af-chat-pills-row af-thread-pills-row"});g.setCssStyles({display:"none"});let w=()=>{if(g.empty(),p.length===0&&m.length===0){g.setCssStyles({display:"none"});return}g.setCssStyles({display:"flex"});for(let x of p){let _=g.createDiv({cls:"af-chat-pill"}),R=_.createSpan({cls:"af-chat-pill-icon"});(0,G.setIcon)(R,"file-text"),_.createSpan({cls:"af-chat-pill-name",text:x.name});let O=_.createSpan({cls:"af-chat-pill-remove"});(0,G.setIcon)(O,"x"),O.onclick=F=>{F.stopPropagation();let B=p.findIndex(q=>q.path===x.path);B>=0&&p.splice(B,1),w()}}for(let x of m){let _=g.createDiv({cls:"af-chat-pill"}),R=_.createSpan({cls:"af-chat-pill-icon"});(0,G.setIcon)(R,"image"),_.createSpan({cls:"af-chat-pill-name",text:x.name});let O=_.createSpan({cls:"af-chat-pill-remove"});(0,G.setIcon)(O,"x"),O.onclick=F=>{F.stopPropagation();let B=m.findIndex(q=>q.path===x.path);B>=0&&m.splice(B,1),w()}}},y=()=>{let x=this.app.workspace.getActiveFile();if(!x){new G.Notice("No active document to attach");return}if(p.some(R=>R.path===x.path)){new G.Notice(`"${x.name}" is already attached`);return}if(!new Set(["md","txt","json","yaml","yml","toml","csv","xml","html","css","js","ts","py","sh","sql","env","cfg","ini","log"]).has(x.extension.toLowerCase())){new G.Notice(`Can't attach "${x.name}" \u2014 only text files are supported`);return}p.push(x),w()},v=async x=>{let _=x.type.split("/")[1]?.replace("jpeg","jpg")??"png",R=x.name&&x.name!=="image"?x.name:`pasted-${Date.now()}.${_}`;if(m.some(F=>F.name===R)){new G.Notice(`"${R}" is already attached`);return}let O=await this.saveImageBlobToVault(x);O&&(m.push(O),w())},k=f.createDiv({cls:"af-chat-input-row af-thread-composer"}),b=k.createEl("button",{cls:"af-chat-attach-btn"});T(b,"plus","af-btn-icon"),b.title="Attach active document",b.onclick=x=>{x.preventDefault(),y()};let P=k.createEl("textarea",{cls:"af-chat-input af-thread-input",attr:{placeholder:"Message in thread\u2026 (Shift+Enter for newline)",rows:"1"}});P.addEventListener("paste",x=>{let _=x.clipboardData?.items;if(_)for(let R=0;R<_.length;R++){let O=_[R];if(O.type.startsWith("image/")){x.preventDefault();let F=O.getAsFile();F&&v(F);return}}}),f.addEventListener("dragover",x=>{x.preventDefault(),x.stopPropagation(),f.addClass("af-chat-input-dragover")}),f.addEventListener("dragleave",()=>{f.removeClass("af-chat-input-dragover")}),f.addEventListener("drop",x=>{x.preventDefault(),x.stopPropagation(),f.removeClass("af-chat-input-dragover");let _=x.dataTransfer?.files;if(_)for(let R=0;R<_.length;R++){let O=_[R];O.type.startsWith("image/")&&v(O)}});let A=k.createEl("button",{cls:"af-chat-send-btn"});T(A,"arrow-up","af-btn-icon"),A.setCssStyles({display:"none"});let M=()=>{P.setCssStyles({height:"auto"}),P.setCssStyles({height:`${Math.min(P.scrollHeight,120)}px`}),A.setCssStyles({display:P.value.trim()?"flex":"none"})};P.addEventListener("input",M),P.addEventListener("focus",()=>this.setStatsSource(s));let E=async()=>{let x=P.value.trim();if(!x||s.isStreaming)return;let _=await this.buildAttachmentContextFor(p,m),R=[...p.map(q=>q.name),...m.map(q=>q.name)],O=_?`${_}${x}`:void 0;P.value="",M(),p.length=0,m.length=0,w(),h("user",x,R.length>0?R:void 0),u(!0);let F=null,B="";try{await s.sendMessage(x,q=>{if(q.type==="text"){F||(u(!1),d(),F=h("assistant",""),F.empty()),B+=q.content;let oe=F.querySelector(".af-chat-stream-text");oe||(oe=F.createDiv({cls:"af-chat-stream-text"})),oe.setText(B)}else q.type==="tool_use"?d(q.toolName):q.type==="result"&&(d(),u(!1),F&&this.renderMarkdownBubble(F,Jt(B)))},O,R.length>0?R:void 0),r()}catch(q){u(!1),d();let oe=q instanceof Error?q.message:String(q);o.createDiv({cls:"af-thread-error",text:`Error: ${oe}`})}};A.onclick=()=>void E(),P.onkeydown=x=>{x.key==="Enter"&&!x.shiftKey&&!x.isComposing&&(x.preventDefault(),E())}}buildToolSummary(t,s){let r=(s??this.messagesInner).createDiv({cls:"af-chat-tool-summary"}),i=r.createEl("details"),o=i.createEl("summary"),l=new Map;for(let u of t){let h=l.get(u.name)??[];u.command&&h.push(u.command),l.set(u.name,h)}let c=o.createSpan({cls:"af-chat-tool-icon"});(0,G.setIcon)(c,"wrench"),o.appendText(` ${t.length} tool call${t.length!==1?"s":""}`);let d=i.createDiv({cls:"af-chat-tool-list"});for(let[u,h]of l){let p=h.length||(l.get(u)?.length??1),m=d.createDiv({cls:"af-chat-tool-item"}),f=p>1?`${u} (\xD7${p})`:u;m.createSpan({cls:"af-chat-tool-name",text:f}),h.length===1&&h[0]&&m.createSpan({cls:"af-chat-tool-cmd",text:h[0]})}return r}renderIndicators(t){let s=t.isStreaming,n=t.currentToolName,r=t.hasCurrentTurnText,i=!!this.messagesInner.querySelector(".af-chat-stream-text"),o=null;if(s&&n?o=`Working\u2026 (${n})`:s&&r&&!i&&(o="Replying\u2026"),o?(this.activityEl?(this.activityEl.parentElement!==this.messagesInner||this.activityEl.nextElementSibling!==null)&&this.messagesInner.appendChild(this.activityEl):this.activityEl=this.messagesInner.createDiv({cls:"af-chat-activity"}),this.activityEl.textContent!==o&&this.activityEl.setText(o)):this.activityEl&&(this.activityEl.remove(),this.activityEl=null),s&&!n&&!r)if(this.streamingDot)(this.streamingDot.parentElement!==this.messagesInner||this.streamingDot.nextElementSibling!==null)&&this.messagesInner.appendChild(this.streamingDot);else{this.streamingDot=this.messagesInner.createDiv({cls:"af-chat-streaming-dot"});for(let c=0;c<3;c++)this.streamingDot.createSpan()}else this.streamingDot&&(this.streamingDot.remove(),this.streamingDot=null);this.setAttachStopMode(s)}setAttachStopMode(t){t!==this.isInStopMode&&(this.isInStopMode=t,this.attachStopBtn.empty(),t?(T(this.attachStopBtn,"square","af-btn-icon"),this.attachStopBtn.title="Stop generation",this.attachStopBtn.addClass("af-chat-stop-mode")):(T(this.attachStopBtn,"plus","af-btn-icon"),this.attachStopBtn.title="Attach active document",this.attachStopBtn.removeClass("af-chat-stop-mode")))}handleStop(){let t=this.getCurrentSession();t&&(t.session.abort(),this.addBubble("error","Generation stopped"))}attachActiveDocument(){let t=this.app.workspace.getActiveFile();if(!t){new G.Notice("No active document to attach");return}if(this.attachedFiles.some(r=>r.path===t.path)){new G.Notice(`"${t.name}" is already attached`);return}let s=t.extension.toLowerCase();if(!new Set(["md","txt","json","yaml","yml","toml","csv","xml","html","css","js","ts","py","sh","sql","env","cfg","ini","log"]).has(s)){new G.Notice(`Can't attach "${t.name}" \u2014 only text files are supported`);return}this.attachedFiles.push(t),this.renderPills()}async saveImageBlobToVault(t){let s=t.type.split("/")[1]?.replace("jpeg","jpg")??"png",n=Date.now(),r=t.name&&t.name!=="image"?t.name:`pasted-${n}.${s}`,i=`${this.plugin.settings.fleetFolder}/chat-images`,o=`${i}/${n}-${r}`;try{this.app.vault.getAbstractFileByPath(i)||await this.app.vault.createFolder(i);let l=await t.arrayBuffer();await this.app.vault.createBinary(o,l);let d=this.app.vault.adapter.getBasePath?.()??"";return{name:r,path:`${d}/${o}`}}catch(l){let c=l instanceof Error?l.message:String(l);return new G.Notice(`Failed to save image: ${c}`),null}}async buildAttachmentContextFor(t,s){if(t.length===0&&s.length===0)return"";let n=[];for(let r of t)try{let i=await this.app.vault.cachedRead(r);n.push(`### ${r.name}
|
|
12041
12028
|
\`\`\`
|
|
12042
12029
|
${i}
|
|
12043
|
-
\`\`\``)}catch{n.push(`### ${
|
|
12044
|
-
(Could not read file)`)}for(let
|
|
12045
|
-
The image file is located at: ${
|
|
12030
|
+
\`\`\``)}catch{n.push(`### ${r.name}
|
|
12031
|
+
(Could not read file)`)}for(let r of s)n.push(`### Image: ${r.name}
|
|
12032
|
+
The image file is located at: ${r.path}
|
|
12046
12033
|
Please read and analyze this image.`);return`## Attached Files
|
|
12047
12034
|
|
|
12048
12035
|
${n.join(`
|
|
@@ -12051,6 +12038,6 @@ ${n.join(`
|
|
|
12051
12038
|
|
|
12052
12039
|
---
|
|
12053
12040
|
|
|
12054
|
-
`}async attachImageBlob(
|
|
12041
|
+
`}async attachImageBlob(t){let s=t.type.split("/")[1]?.replace("jpeg","jpg")??"png",n=t.name&&t.name!=="image"?t.name:`pasted-${Date.now()}.${s}`;if(this.attachedImages.some(i=>i.name===n)){new G.Notice(`"${n}" is already attached`);return}let r=await this.saveImageBlobToVault(t);r&&(this.attachedImages.push(r),this.renderPills())}removeAttachment(t){this.attachedFiles=this.attachedFiles.filter(s=>s.path!==t),this.attachedImages=this.attachedImages.filter(s=>s.path!==t),this.renderPills()}renderPills(){if(this.pillsRow.empty(),this.attachedFiles.length+this.attachedImages.length===0){this.pillsRow.setCssStyles({display:"none"});return}this.pillsRow.setCssStyles({display:"flex"});for(let s of this.attachedFiles){let n=this.pillsRow.createDiv({cls:"af-chat-pill"}),r=n.createSpan({cls:"af-chat-pill-icon"});(0,G.setIcon)(r,"file-text"),n.createSpan({cls:"af-chat-pill-name",text:s.name});let i=n.createSpan({cls:"af-chat-pill-remove"});(0,G.setIcon)(i,"x"),i.onclick=o=>{o.stopPropagation(),this.removeAttachment(s.path)}}for(let s of this.attachedImages){let n=this.pillsRow.createDiv({cls:"af-chat-pill"}),r=n.createSpan({cls:"af-chat-pill-icon"});(0,G.setIcon)(r,"image"),n.createSpan({cls:"af-chat-pill-name",text:s.name});let i=n.createSpan({cls:"af-chat-pill-remove"});(0,G.setIcon)(i,"x"),i.onclick=o=>{o.stopPropagation(),this.removeAttachment(s.path)}}}buildAttachmentContext(){return this.buildAttachmentContextFor(this.attachedFiles,this.attachedImages)}async handleSend(){let t=this.getCurrentSession();if(!t)return;let s=this.textarea.value.trim();if(!s)return;let n=await this.buildAttachmentContext(),r=[...this.attachedFiles.map(h=>h.name),...this.attachedImages.map(h=>h.name)];this.textarea.value="",this.textarea.setCssStyles({height:"auto"}),this.sendBtn.setCssStyles({display:"none"}),this.attachedFiles=[],this.attachedImages=[],this.renderPills();let i=n?`${n}${s}`:void 0;if(this.addBubble("user",s,r.length>0?r:void 0),t.session.isStreaming){t.session.injectMessage(s,i,r.length>0?r:void 0);return}let o=null,l="",c=!1,d=t.session,u=()=>this.getCurrentSession()?.session===d;try{await t.session.sendMessage(s,h=>{if(!u()){o=null,c=!1,l="";return}if(h.type==="text"){(!c||!o||!o.isConnected)&&(o=this.addBubble("assistant"),c=!0),l+=h.content;let p=o.querySelector(".af-chat-stream-text");p||(p=o.createDiv({cls:"af-chat-stream-text"})),p.setText(l)}else if(h.type==="error"){let p=h.errorMessage?.trim()||"The agent's run ended with an error.";this.addErrorBubble(p)}else if(h.type!=="compacted"){if(h.type==="result"){if(c&&o&&o.isConnected){let p=Jt(l);this.renderMarkdownBubble(o,p),o._setRawText?.(p);let m=t.session.messages[t.session.messages.length-1];if(m&&m.role==="assistant"&&(this.attachThreadAffordance(o,m.id,t.session),h.toolCalls&&h.toolCalls.length>0)){let f=this.getOrCreateAffordancesRow(o);this.buildToolSummary(h.toolCalls,f)}}else h.toolCalls&&h.toolCalls.length>0&&this.buildToolSummary(h.toolCalls);l="",c=!1,o=null}}},i,r.length>0?r:void 0)}catch(h){let p=h instanceof Error?h.message:String(h);p!=="Aborted"&&this.addErrorBubble(p)}}addErrorBubble(t){let s=this.addBubble("error",`Error: ${t}`),n=wp(t);n&&s.createDiv({cls:"af-chat-error-hint",text:n})}async handleNewChat(){if(!this.selectedAgentName)return;let s=this.plugin.runtime.getSnapshot().agents.find(r=>r.name===this.selectedAgentName);if(!s)return;let n=Ic();try{await this.plugin.repository.createConversation(s,n,Mc())}catch(r){new G.Notice(`Couldn't create conversation: ${r instanceof Error?r.message:String(r)}`);return}await this.switchToAgent(this.selectedAgentName,n)}startFreshIntro(t){let s="",n=null,r=!1;t.sendMessage("Please introduce yourself and briefly describe your capabilities and what you can help with.",i=>{i.type==="text"&&(r||(n=this.addBubble("assistant"),r=!0),s+=i.content,n.setText(s))}).then(i=>{r&&n?(this.renderMarkdownBubble(n,s),n._setRawText?.(s)):i.text.trim()&&(n=this.addBubble("assistant"),this.renderMarkdownBubble(n,i.text),n._setRawText?.(i.text)),i.toolCalls.length>0&&this.buildToolSummary(i.toolCalls),this.textarea.focus()}).catch(i=>{let o=i instanceof Error?i.message:String(i);o!=="Aborted"&&this.addErrorBubble(o)})}};function wp(a){let e=a.toLowerCase();return/context\s*(window|length)|prompt is too long|too many tokens|token limit|maximum context|context.{0,20}exceed/.test(e)?"Try a smaller model, or start a new session to clear history.":/rate.?limit|\b429\b|overloaded|too many requests/.test(e)?"Wait a minute and retry, or check your API quota.":/\b401\b|unauthorized|api.?key|authentication|invalid.{0,10}credential|not logged in/.test(e)?"Check your API key / CLI login (run the CLI's login command in a terminal).":/timed out|time.?out|watchdog/.test(e)?"A tool may be stuck. Retry, or raise the Chat Watchdog Timeout in Settings.":/enoent|command not found|no such file or directory/.test(e)?"CLI binary not found \u2014 check the CLI path in Settings.":null}function Ds(a){return a>=1e3?`${(a/1e3).toFixed(a>=1e4?0:1)}k`:`${a}`}var Ra=class a extends pe.Plugin{settings={...ft};repository;runtime;get mcpManager(){return this.runtime.mcpManager}mcpAuth=new ea;channelCredentials=new aa;channelManager;secretStore;cliVerifiedAt=new Map;static CLI_VERIFY_TTL_MS=5*6e4;statusBarEl;subscribedViews=new Set;vaultChangeTimer;suppressVaultEvents=!1;suppressTimer;runtimeUnsubscribe;async onload(){await this.loadSettings(),this.settings.claudeCliPath=await this.resolveClaudeCliPath(this.settings.claudeCliPath),this.repository=new Us(this.app,this.settings),this.repository.setChannelCredentialGetter(()=>this.channelCredentials.toRecord()),this.runtime=new Ys(this.repository,this.settings,this.mcpAuth),this.registerView(Yt,r=>new un(r,this)),this.registerView(us,r=>new Sa(r,this)),this.registerView(mt,r=>new Rs(r,this)),this.addSettingTab(new Un(this)),await this.repository.ensureFleetStructure()&&await this.repository.ensureSamples();let t=await this.repository.updateDefaults(this.settings.defaultFileHashes??{});JSON.stringify(t)!==JSON.stringify(this.settings.defaultFileHashes??{})&&(this.settings.defaultFileHashes=t,await this.saveData(this.settings));let s=await this.repository.migrateUsageLedgerCosts();s&&s.changed>0&&console.log(`Agent Fleet: repaired ${s.changed} usage-ledger cost rows across ${s.files} day(s).`),await this.runtime.initialize(),await this.verifyClaudeCli(!1),await this.maybeResolveCodexCliPath(),this.addRibbonIcon("bot","Agent Fleet Dashboard",()=>void this.activateDashboardView()),this.addRibbonIcon("message-circle","Agent Chat",()=>{let r=this.app.workspace.getLeavesOfType(mt);r.length>0?this.app.workspace.revealLeaf(r[0]):this.openChatView()}),this.addCommands(),this.registerVaultHandlers(),this.registerRuntimeListeners();let n=this.app.secretStorage;if(this.secretStore=new Zn(n),this.channelCredentials.setSecretStore(this.secretStore),this.mcpAuth.setSecretStore(this.secretStore),!this.settings.secretsMigrated&&this.secretStore.available){this.channelCredentials.loadCredentials(this.settings.channelCredentials??{});for(let[r,i]of Object.entries(this.settings.mcpApiKeys??{}))typeof i=="string"&&i.trim()&&this.mcpAuth.storeStaticToken(r,i);this.settings.mcpTokens={},this.settings.mcpApiKeys={},this.settings.channelCredentials={},this.settings.secretsMigrated=!0,await this.saveData(this.settings)}else this.channelCredentials.loadCredentials(this.secretStore.available?void 0:this.settings.channelCredentials??{});this.secretStore.available||this.channelCredentials.onChanged(r=>{this.settings.channelCredentials=r,this.saveSettings()}),this.channelManager=new na({getRepository:()=>this.repository,vault:this.app.vault,getSettings:()=>this.settings,getChannelCredentials:()=>this.channelCredentials.toRecord(),getMcpAuth:()=>this.mcpAuth,recordUsage:r=>this.runtime.recordUsage(r),adapterFactory:(r,i)=>{if(r.type==="slack")return new ba(r,i);if(r.type==="telegram")return new ka(r,i);if(r.type==="discord")return new xa(r,i);throw new Error(`Channel type \`${r.type}\` is not yet supported in this version.`)}});try{await this.channelManager.start(this.runtime.getSnapshot())}catch(r){console.error("Agent Fleet: channel manager failed to start",r),new pe.Notice("Agent Fleet: channel manager failed to start \u2014 check console.")}this.runtime.onChannelResult((r,i,o,l,c)=>{let u=`*${l==="heartbeat"?`Heartbeat \u2014 ${r}`:`${r} \u2014 ${l}`}*
|
|
12055
12042
|
|
|
12056
|
-
${o}`;(l?this.channelManager?.postToChannelTarget(i,l,d):this.channelManager?.broadcastToChannel(i,d))?.catch(p=>{console.warn(`Agent Fleet: channel post failed for ${a}`,p)})}),this.refreshStatusBar(),this.importNativeMcpServers(),this.registerInterval(window.setInterval(()=>void this.mcpManager.refreshProbeTokens(),30*6e4)),new Se.Notice("Agent Fleet loaded.")}async importNativeMcpServers(){if(this.settings.mcpImported)return;if(this.repository.getMcpServers().length>0){this.settings.mcpImported=!0,await this.saveData(this.settings);return}let t=n=>{try{return(0,Os.existsSync)(n)?(0,Os.readFileSync)(n,"utf-8"):null}catch{return null}},e=t((0,Qa.join)((0,Xa.homedir)(),".claude.json")),s=t((0,Qa.join)((0,Xa.homedir)(),".codex","config.toml"));try{let n=_i(e?Ci(e):{servers:[],tokens:{}},s?Ti(s):{servers:[],tokens:{}}),a=0;for(let i of n.servers)try{await this.repository.saveMcpServer(i,i.description??"");let o=n.tokens[i.name];o&&this.mcpAuth.storeStaticToken(i.name,o),a++}catch(o){console.warn(`Agent Fleet: failed to import MCP server "${i.name}":`,o)}this.settings.mcpImported=!0,await this.saveData(this.settings),a>0&&(await this.refreshFromVault(),new Se.Notice(`Agent Fleet: imported ${a} MCP server${a===1?"":"s"}.`))}catch(n){console.error("Agent Fleet: MCP import failed",n)}}onunload(){this.runtimeUnsubscribe?.(),this.runtimeUnsubscribe=void 0,this.vaultChangeTimer&&(window.clearTimeout(this.vaultChangeTimer),this.vaultChangeTimer=void 0),this.suppressTimer&&(window.clearTimeout(this.suppressTimer),this.suppressTimer=void 0),this.runtime?.shutdown(),this.channelManager?.stop(),Zr()}async loadSettings(){this.settings={...it,...await this.loadData()}}async saveSettings(){this.settings.claudeCliPath=await this.resolveClaudeCliPath(this.settings.claudeCliPath),await this.maybeResolveCodexCliPath(),ei(),await this.saveData(this.settings),this.repository&&this.runtime&&(this.runtime.shutdown(),this.repository=new ps(this.app,this.settings),this.repository.setChannelCredentialGetter(()=>this.channelCredentials.toRecord()),this.runtime=new ks(this.repository,this.settings,this.mcpAuth),await this.repository.ensureFleetStructure(),await this.runtime.initialize(),this.registerRuntimeListeners(),this.notifyViews(),this.refreshStatusBar(),this.channelCredentials.loadCredentials(this.secretStore.available?void 0:this.settings.channelCredentials??{}),this.channelManager?.reconcile(this.runtime.getSnapshot()))}subscribeView(t){this.subscribedViews.add(t)}unsubscribeView(t){this.subscribedViews.delete(t)}async activateDashboardView(){let t=this.app.workspace.getLeavesOfType(_t);if(t.length>0){this.app.workspace.revealLeaf(t[0]);return}await this.app.workspace.getLeaf(!0).setViewState({type:_t,active:!0})}async navigateDashboard(t,e){await this.activateDashboardView();let n=this.app.workspace.getLeavesOfType(_t)[0];if(n){let a=n.view;a instanceof Fs&&a.navigateTo(t,e)}}async activateAgentsView(){let t=this.getLeafForView(jt,"left");await t.setViewState({type:jt,active:!0}),this.app.workspace.revealLeaf(t)}async openChatView(t){if(t){let s=this.app.workspace.getLeavesOfType(rt);for(let n of s)if(n.view instanceof os&&n.view.selectedAgentName===t){this.app.workspace.revealLeaf(n);return}}let e=this.app.workspace.getRightLeaf(!1)??this.app.workspace.getLeaf(!0);await e.setViewState({type:rt,active:!0,state:t?{agentName:t}:{}}),this.app.workspace.revealLeaf(e),t&&e.view instanceof os&&e.view.selectAgent(t)}async refreshFromVault(){this.suppressVaultEvents=!0;try{await this.runtime.refreshFromVault(),this.notifyViews(),this.refreshStatusBar(),this.channelManager?.reconcile(this.runtime.getSnapshot())}finally{this.suppressTimer&&window.clearTimeout(this.suppressTimer),this.suppressTimer=window.setTimeout(()=>{this.suppressTimer=void 0,this.suppressVaultEvents=!1},500)}}refreshStatusBar(){if(!this.settings.showStatusBar){this.statusBarEl?.detach(),this.statusBarEl=void 0;return}this.statusBarEl||(this.statusBarEl=this.addStatusBarItem(),this.statusBarEl.onclick=()=>void this.activateDashboardView());let t=this.runtime.getFleetStatus();this.statusBarEl.setText(`\u{1F916} ${t.running} running \xB7 ${t.pending} pending \xB7 ${t.completedToday} completed today`)}async verifyClaudeCli(t=!0){let e=await this.resolveClaudeCliPath(this.settings.claudeCliPath);return this.settings.claudeCliPath=e,await this.verifyCliBinary(e,"Claude",t)}async verifyCodexCli(t=!0){let e=await this.resolveCliPathFrom(ta(this.settings.codexCliPath),this.settings.codexCliPath);return this.settings.codexCliPath=e,await this.verifyCliBinary(e,"Codex",t)}async verifyCliBinary(t,e,s){return await new Promise(n=>{let a=dt(t,["--version"]),i="";a.stderr.on("data",o=>{i+=o.toString()}),a.on("close",o=>{let c=o===0;c||console.error(`Agent Fleet: ${e} CLI verification failed`,i),s&&new Se.Notice(c?`${e} CLI available.`:`${e} CLI verification failed \u2014 check ${e} CLI Path in settings.`),n(c)}),a.on("error",o=>{console.error(`Agent Fleet: ${e} CLI verification error`,o),s&&new Se.Notice(`${e} CLI verification failed \u2014 check ${e} CLI Path in settings.`),n(!1)})})}async openPath(t){let e=this.app.vault.getAbstractFileByPath((0,Se.normalizePath)(t));e instanceof Se.TFile&&await this.app.workspace.getLeaf(!0).openFile(e)}async createAgentTemplate(){await this.navigateDashboard("create-agent")}async createSkillTemplate(){await this.navigateDashboard("create-skill")}async openCreateTask(){await this.navigateDashboard("create-task")}async runAgentPrompt(t){let e=this.repository.getAgentByName(t);if(!e){new Se.Notice(`Unknown agent: ${t}`);return}await this.runtime.runAgentNow(e,"Run now and summarize the current state.")}async chatWithAgent(t){if(!this.repository.getAgentByName(t)){new Se.Notice(`Unknown agent: ${t}`);return}await this.openChatView(t)}async deleteAgent(t){if(!this.repository.getAgentByName(t)){new Se.Notice(`Unknown agent: ${t}`);return}let s=this.repository.getTasksForAgent(t),n=this.runtime.getRecentRuns().filter(o=>o.agent===t),a=this.repository.getMemoryPath(t),i=!!this.app.vault.getAbstractFileByPath(a);new Ks(this.app,{agentName:t,taskCount:s.length,runCount:n.length,hasMemory:i},async o=>{let c=await this.repository.deleteAgent(t,o);await new Promise(l=>window.setTimeout(l,200)),await this.refreshFromVault(),new Se.Notice(`Deleted agent "${t}" (${c.trashedFiles.length} files moved to trash)`),await this.navigateDashboard("agents")}).open()}async toggleAgent(t,e){let s=this.repository.getAgentByName(t);if(!s)return;let n=this.app.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof Se.TFile))return;let a=await this.app.vault.cachedRead(n),{frontmatter:i,body:o}=J(a);i.enabled=e,await this.app.vault.modify(n,H(i,o)),await this.refreshFromVault()}addCommands(){this.addCommand({id:"open-dashboard",name:"Open dashboard",callback:()=>void this.activateDashboardView()}),this.addCommand({id:"open-agents-panel",name:"Open agents panel",callback:()=>void this.activateAgentsView()}),this.addCommand({id:"open-chat",name:"Open agent chat",callback:()=>{let t=this.app.workspace.getLeavesOfType(rt);t.length>0?this.app.workspace.revealLeaf(t[0]):this.openChatView()}}),this.addCommand({id:"new-chat-tab",name:"New chat tab",callback:()=>void this.openChatView()}),this.addCommand({id:"new-agent",name:"New agent",callback:()=>void this.createAgentTemplate()}),this.addCommand({id:"new-skill",name:"New skill",callback:()=>void this.createSkillTemplate()}),this.addCommand({id:"new-task",name:"New task",callback:()=>void this.openCreateTask()}),this.addCommand({id:"run-agent-now",name:"Run agent now",callback:()=>{let t=this.runtime.getSnapshot().agents[0];t?this.runAgentPrompt(t.name):new Se.Notice("No agents configured.")}}),this.addCommand({id:"pause-all",name:"Pause all",callback:()=>{this.runtime.scheduler.pauseAll(),new Se.Notice("Agent Fleet paused.")}}),this.addCommand({id:"resume-all",name:"Resume all",callback:()=>{this.runtime.scheduler.resumeAll(),new Se.Notice("Agent Fleet resumed.")}}),this.addCommand({id:"view-fleet-status",name:"View status",callback:()=>{let t=this.runtime.getFleetStatus();new Se.Notice(`${t.running} running \xB7 ${t.pending} pending \xB7 ${t.completedToday} completed today`)}})}debouncedVaultRefresh(){this.suppressVaultEvents||(this.vaultChangeTimer&&window.clearTimeout(this.vaultChangeTimer),this.vaultChangeTimer=window.setTimeout(()=>{this.suppressVaultEvents||this.refreshFromVault()},500))}registerVaultHandlers(){let t=e=>e.startsWith(`${this.settings.fleetFolder}/usage/`);this.registerEvent(this.app.vault.on("create",e=>{e instanceof Se.TFile&&e.path.startsWith(`${this.settings.fleetFolder}/`)&&!t(e.path)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("modify",e=>{e instanceof Se.TFile&&e.path.startsWith(`${this.settings.fleetFolder}/`)&&!t(e.path)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("rename",e=>{e.path.startsWith(`${this.settings.fleetFolder}/`)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("delete",e=>{e.path.startsWith(`${this.settings.fleetFolder}/`)&&this.debouncedVaultRefresh()}))}registerRuntimeListeners(){this.runtimeUnsubscribe?.(),this.runtimeUnsubscribe=this.runtime.subscribe(()=>{this.notifyViews(),this.refreshStatusBar()})}notifyViews(){for(let t of this.subscribedViews)t.render()}async resolveClaudeCliPath(t){return this.resolveCliPathFrom(Tr(t),t)}async maybeResolveCodexCliPath(){this.runtime?.getSnapshot().agents.some(e=>kt(e.adapter)==="codex")&&(this.settings.codexCliPath=await this.resolveCliPathFrom(ta(this.settings.codexCliPath),this.settings.codexCliPath))}async resolveCliPathFrom(t,e){for(let s of t)if(sa(s)&&(0,Os.existsSync)(s)||!sa(s)&&await new Promise(a=>{let i=dt(s,["--version"]);i.on("close",o=>a(o===0)),i.on("error",()=>a(!1))}))return s;return e}getLeafForView(t,e){let s=this.app.workspace.getLeavesOfType(t)[0];return s||(e==="right"?this.app.workspace.getRightLeaf(!1)??this.app.workspace.getLeaf(!0):this.app.workspace.getLeftLeaf(!1)??this.app.workspace.getLeaf(!1))}};
|
|
12043
|
+
${o}`;(c?this.channelManager?.postToChannelTarget(i,c,u):this.channelManager?.broadcastToChannel(i,u))?.catch(p=>{console.warn(`Agent Fleet: channel post failed for ${r}`,p)})}),this.refreshStatusBar(),this.importNativeMcpServers(),this.cleanupStaleTempFiles().catch(r=>{console.warn("Agent Fleet: stale temp-file sweep failed",r)}),this.registerInterval(window.setInterval(()=>void this.mcpManager.refreshProbeTokens(),30*6e4)),new pe.Notice("Agent Fleet loaded.")}async importNativeMcpServers(){if(this.settings.mcpImported)return;if(this.repository.getMcpServers().length>0){this.settings.mcpImported=!0,await this.saveData(this.settings);return}let e=n=>{try{return(0,hn.existsSync)(n)?(0,hn.readFileSync)(n,"utf-8"):null}catch{return null}},t=e((0,Is.join)((0,pn.homedir)(),".claude.json")),s=e((0,Is.join)((0,pn.homedir)(),".codex","config.toml"));try{let n=Eo(t?Ao(t):{servers:[],tokens:{}},s?Po(s):{servers:[],tokens:{}}),r=0;for(let i of n.servers)try{await this.repository.saveMcpServer(i,i.description??"");let o=n.tokens[i.name];o&&this.mcpAuth.storeStaticToken(i.name,o),r++}catch(o){console.warn(`Agent Fleet: failed to import MCP server "${i.name}":`,o)}this.settings.mcpImported=!0,await this.saveData(this.settings),r>0&&(await this.refreshFromVault(),new pe.Notice(`Agent Fleet: imported ${r} MCP server${r===1?"":"s"}.`))}catch(n){console.error("Agent Fleet: MCP import failed",n)}}onunload(){this.runtimeUnsubscribe?.(),this.runtimeUnsubscribe=void 0,this.vaultChangeTimer&&(window.clearTimeout(this.vaultChangeTimer),this.vaultChangeTimer=void 0),this.suppressTimer&&(window.clearTimeout(this.suppressTimer),this.suppressTimer=void 0),this.runtime?.shutdown(),this.channelManager?.stop(),Xi()}async loadSettings(){this.settings={...ft,...await this.loadData()}}async saveSettings(){this.settings.claudeCliPath=await this.resolveClaudeCliPath(this.settings.claudeCliPath),await this.maybeResolveCodexCliPath(),Qi(),await this.saveData(this.settings),this.repository&&this.runtime&&(this.runtime.shutdown(),this.repository=new Us(this.app,this.settings),this.repository.setChannelCredentialGetter(()=>this.channelCredentials.toRecord()),this.runtime=new Ys(this.repository,this.settings,this.mcpAuth),await this.repository.ensureFleetStructure(),await this.runtime.initialize(),this.registerRuntimeListeners(),this.notifyViews(),this.refreshStatusBar(),this.channelCredentials.loadCredentials(this.secretStore.available?void 0:this.settings.channelCredentials??{}),this.channelManager?.reconcile(this.runtime.getSnapshot()))}subscribeView(e){this.subscribedViews.add(e)}unsubscribeView(e){this.subscribedViews.delete(e)}async activateDashboardView(){let e=this.app.workspace.getLeavesOfType(Yt);if(e.length>0){this.app.workspace.revealLeaf(e[0]);return}await this.app.workspace.getLeaf(!0).setViewState({type:Yt,active:!0})}async navigateDashboard(e,t){await this.activateDashboardView();let n=this.app.workspace.getLeavesOfType(Yt)[0];if(n){let r=n.view;r instanceof un&&r.navigateTo(e,t)}}async activateAgentsView(){let e=this.getLeafForView(us,"left");await e.setViewState({type:us,active:!0}),this.app.workspace.revealLeaf(e)}async openChatView(e){if(e){let s=this.app.workspace.getLeavesOfType(mt);for(let n of s)if(n.view instanceof Rs&&n.view.selectedAgentName===e){this.app.workspace.revealLeaf(n);return}}let t=this.app.workspace.getRightLeaf(!1)??this.app.workspace.getLeaf(!0);await t.setViewState({type:mt,active:!0,state:e?{agentName:e}:{}}),this.app.workspace.revealLeaf(t),e&&t.view instanceof Rs&&t.view.selectAgent(e)}async refreshFromVault(){this.suppressVaultEvents=!0;try{await this.runtime.refreshFromVault(),this.notifyViews(),this.refreshStatusBar(),this.channelManager?.reconcile(this.runtime.getSnapshot())}finally{this.suppressTimer&&window.clearTimeout(this.suppressTimer),this.suppressTimer=window.setTimeout(()=>{this.suppressTimer=void 0,this.suppressVaultEvents=!1},500)}}refreshStatusBar(){if(!this.settings.showStatusBar){this.statusBarEl?.detach(),this.statusBarEl=void 0;return}this.statusBarEl||(this.statusBarEl=this.addStatusBarItem(),this.statusBarEl.onclick=()=>void this.activateDashboardView());let e=this.runtime.getFleetStatus();this.statusBarEl.setText(`\u{1F916} ${e.running} running \xB7 ${e.pending} pending \xB7 ${e.completedToday} completed today`)}async verifyClaudeCli(e=!0){let t=await this.resolveClaudeCliPath(this.settings.claudeCliPath);return this.settings.claudeCliPath=t,await this.verifyCliBinary(t,"Claude",e)}async verifyCodexCli(e=!0){let t=await this.resolveCliPathFrom(za(this.settings.codexCliPath),this.settings.codexCliPath);return this.settings.codexCliPath=t,await this.verifyCliBinary(t,"Codex",e)}async verifyCliBinary(e,t,s){let n=`${t}:${e}`,r=this.cliVerifiedAt.get(n);if(r!==void 0&&Date.now()-r<a.CLI_VERIFY_TTL_MS)return s&&new pe.Notice(`${t} CLI available.`),!0;let o=`${t} CLI verification failed (path: ${e||"not set"}). Fix the ${t} CLI Path in settings, or ${t==="Claude"?"install with: npm install -g @anthropic-ai/claude-code":"install with: npm install -g @openai/codex"}`;return await new Promise(l=>{let c=wt(e,["--version"]),d="";c.stderr.on("data",u=>{d+=u.toString()}),c.on("close",u=>{let h=u===0;h?this.cliVerifiedAt.set(n,Date.now()):console.error(`Agent Fleet: ${t} CLI verification failed`,d),s&&new pe.Notice(h?`${t} CLI available.`:o,h?5e3:1e4),l(h)}),c.on("error",u=>{console.error(`Agent Fleet: ${t} CLI verification error`,u),s&&new pe.Notice(o,1e4),l(!1)})})}async cleanupStaleTempFiles(){let e=Date.now(),t=async(n,r,i)=>{let o;try{o=await(0,Ms.readdir)(n)}catch{return}for(let l of o){if(!r(l))continue;let c=(0,Is.join)(n,l);try{let d=await(0,Ms.stat)(c);e-d.mtimeMs>i&&await(0,Ms.rm)(c,{recursive:!0,force:!0})}catch{}}},s=this.repository.getVaultBasePath();s&&await t((0,Is.join)(s,".claude"),n=>/^(af-mcp|af-remember-mcp)[.-].+\.(json|cjs)$/.test(n),1440*60*1e3),await t((0,Is.join)((0,pn.tmpdir)(),"agent-fleet-codex"),()=>!0,10080*60*1e3)}async openPath(e){let t=this.app.vault.getAbstractFileByPath((0,pe.normalizePath)(e));t instanceof pe.TFile&&await this.app.workspace.getLeaf(!0).openFile(t)}async createAgentTemplate(){await this.navigateDashboard("create-agent")}async createSkillTemplate(){await this.navigateDashboard("create-skill")}async openCreateTask(){await this.navigateDashboard("create-task")}async runAgentPrompt(e){let t=this.repository.getAgentByName(e);if(!t){new pe.Notice(`Unknown agent: ${e}`);return}await this.runtime.runAgentNow(t,"Run now and summarize the current state.")}async chatWithAgent(e){if(!this.repository.getAgentByName(e)){new pe.Notice(`Unknown agent: ${e}`);return}await this.openChatView(e)}async deleteAgent(e){if(!this.repository.getAgentByName(e)){new pe.Notice(`Unknown agent: ${e}`);return}let s=this.repository.getTasksForAgent(e),n=this.runtime.getRecentRuns().filter(o=>o.agent===e),r=this.repository.getMemoryPath(e),i=!!this.app.vault.getAbstractFileByPath(r);new Fn(this.app,{agentName:e,taskCount:s.length,runCount:n.length,hasMemory:i},async o=>{let l=await this.repository.deleteAgent(e,o);await new Promise(c=>window.setTimeout(c,200)),await this.refreshFromVault(),new pe.Notice(`Deleted agent "${e}" (${l.trashedFiles.length} files moved to trash)`),await this.navigateDashboard("agents")}).open()}async toggleAgent(e,t){let s=this.repository.getAgentByName(e);if(!s)return;let n=this.app.vault.getAbstractFileByPath(s.filePath);if(!(n instanceof pe.TFile))return;let r=await this.app.vault.cachedRead(n),{frontmatter:i,body:o}=W(r);i.enabled=t,await this.app.vault.modify(n,U(i,o)),await this.refreshFromVault()}addCommands(){this.addCommand({id:"open-dashboard",name:"Open dashboard",callback:()=>void this.activateDashboardView()}),this.addCommand({id:"open-agents-panel",name:"Open agents panel",callback:()=>void this.activateAgentsView()}),this.addCommand({id:"open-chat",name:"Open agent chat",callback:()=>{let e=this.app.workspace.getLeavesOfType(mt);e.length>0?this.app.workspace.revealLeaf(e[0]):this.openChatView()}}),this.addCommand({id:"new-chat-tab",name:"New chat tab",callback:()=>void this.openChatView()}),this.addCommand({id:"new-agent",name:"New agent",callback:()=>void this.createAgentTemplate()}),this.addCommand({id:"new-skill",name:"New skill",callback:()=>void this.createSkillTemplate()}),this.addCommand({id:"new-task",name:"New task",callback:()=>void this.openCreateTask()}),this.addCommand({id:"run-agent-now",name:"Run agent now",callback:()=>{let e=this.runtime.getSnapshot().agents[0];e?this.runAgentPrompt(e.name):new pe.Notice("No agents configured.")}}),this.addCommand({id:"pause-all",name:"Pause all",callback:()=>{this.runtime.scheduler.pauseAll(),new pe.Notice("Agent Fleet paused.")}}),this.addCommand({id:"resume-all",name:"Resume all",callback:()=>{this.runtime.scheduler.resumeAll(),new pe.Notice("Agent Fleet resumed.")}}),this.addCommand({id:"view-fleet-status",name:"View status",callback:()=>{let e=this.runtime.getFleetStatus();new pe.Notice(`${e.running} running \xB7 ${e.pending} pending \xB7 ${e.completedToday} completed today`)}})}debouncedVaultRefresh(){this.suppressVaultEvents||(this.vaultChangeTimer&&window.clearTimeout(this.vaultChangeTimer),this.vaultChangeTimer=window.setTimeout(()=>{this.suppressVaultEvents||this.refreshFromVault()},500))}registerVaultHandlers(){let e=t=>t.startsWith(`${this.settings.fleetFolder}/usage/`);this.registerEvent(this.app.vault.on("create",t=>{t instanceof pe.TFile&&t.path.startsWith(`${this.settings.fleetFolder}/`)&&!e(t.path)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("modify",t=>{t instanceof pe.TFile&&t.path.startsWith(`${this.settings.fleetFolder}/`)&&!e(t.path)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("rename",t=>{t.path.startsWith(`${this.settings.fleetFolder}/`)&&this.debouncedVaultRefresh()})),this.registerEvent(this.app.vault.on("delete",t=>{t.path.startsWith(`${this.settings.fleetFolder}/`)&&this.debouncedVaultRefresh()}))}registerRuntimeListeners(){this.runtimeUnsubscribe?.(),this.runtimeUnsubscribe=this.runtime.subscribe(()=>{this.notifyViews(),this.refreshStatusBar()})}notifyViews(){for(let e of this.subscribedViews)e.render()}async resolveClaudeCliPath(e){return this.resolveCliPathFrom(Ai(e),e)}async maybeResolveCodexCliPath(){this.runtime?.getSnapshot().agents.some(t=>Bt(t.adapter)==="codex")&&(this.settings.codexCliPath=await this.resolveCliPathFrom(za(this.settings.codexCliPath),this.settings.codexCliPath))}async resolveCliPathFrom(e,t){for(let s of e)if(Ga(s)&&(0,hn.existsSync)(s)||!Ga(s)&&await new Promise(r=>{let i=wt(s,["--version"]);i.on("close",o=>r(o===0)),i.on("error",()=>r(!1))}))return s;return t}getLeafForView(e,t){let s=this.app.workspace.getLeavesOfType(e)[0];return s||(t==="right"?this.app.workspace.getRightLeaf(!1)??this.app.workspace.getLeaf(!0):this.app.workspace.getLeftLeaf(!1)??this.app.workspace.getLeaf(!1))}};
|