@agent-native/skills 0.1.0 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAY,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAE5E,MAAM,iBAAiB,GAAG,yCAAyC,CAAC;AACpE,MAAM,gBAAgB,GAAG,wCAAwC,CAAC;AAClE,MAAM,QAAQ,GAAG,oBAAoB,CAAC;AAEtC,8EAA8E;AAC9E,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAW;IACjD,aAAa;IACb,iBAAiB;CAClB,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,uBAAuB,GAAG,iCAAiC,CAAC;AA8ElE,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,UAAU,sBAAsB,CAAC,MAAgB;IACrD,OAAO,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,SAAS,CAAC,EAAU;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,gEAAgE;AAChE,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,UAAyB;IAC9C,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,OAAO,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0EAA0E;AAC1E,SAAS,cAAc,CAAC,UAAyB;IAC/C,IAAI,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACxD,OAAO,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,8DAA8D;IAC9D,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,UAAU,CAAC,UAAyB;IAC3C,MAAM,IAAI,GAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC7C,IAAI,KAAK,IAAI,KAAK,KAAK,UAAU,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,SAAS,qBAAqB,CAC5B,OAA2C;IAE3C,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC,uBAAuB,CAAC,EAAE,GAAG,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,eAAe,CAAC,IAAS,EAAE,QAAgB;IAClD,MAAM,OAAO,GACX,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ;QAC/B,CAAC,CAAC,IAAI,CAAC,OAAO;QACd,CAAC,CAAC,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ;YAC/B,CAAC,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC,EAAE,CAAC;IACX,OAAO,OAAO,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,SAAuB,EACvB,GAAW,EACX,IAAa;IAEb,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,IAAI,GAAQ,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,OAAe;IAC7C,OAAO,yCAAyC,OAAO,kBAAkB,CAAC;AAC5E,CAAC;AAED,iFAAiF;AACjF,SAAS,mBAAmB,CAC1B,OAAmB,EACnB,IAAc,EACd,MAAc,EACd,KAAa,EACb,OAAe,EACf,OAA6C,EAC7C,MAAgB;IAEhB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,uBAAuB,CAClC,MAAM,EACN,GAAG,EACH,MAAM,EACN,SAAS,EACT,OAAO,EACP,KAAK,EACL,SAAS,CACV,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CACT,mBAAmB,GAAG,QAAQ,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,SAAS,kBAAkB,CACzB,OAAmB,EACnB,IAAc,EACd,MAAc,EACd,KAAyB,EACzB,OAA2C,EAC3C,KAAa,EACb,OAAe,EACf,OAA6C,EAC7C,MAAgB;IAEhB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,uBAAuB,CAClC,MAAM,EACN,GAAG,EACH,MAAM,EACN,KAAK,EACL,OAAO,EACP,KAAK,EACL,qBAAqB,CAAC,OAAO,CAAC,CAC/B,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CACT,mBAAmB,GAAG,QAAQ,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,kEAAkE;AAClE,8EAA8E;AAE9E;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAC1B,OAAe,EACf,OAAe,EACf,SAAiB,EACjB,GAAwB,EACxB,OAAmC,EAAE;IAErC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAE3C,IAAI,KAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CACrC,SAAS,EACT,GAAG,OAAO,GAAG,iBAAiB,EAAE,EAChC,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,CACpC,CAAC;QACF,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;YACxD,GAAG,CACD,yCAAyC,OAAO,UAAU,MAAM,KAAK;gBACnE,mEAAmE;gBACnE,mBAAmB,CACtB,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,GAAG,IAA2B,CAAC;IACtC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CACD,qBAAqB,OAAO,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,KAAK;YACvD,iCAAiC,CACpC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;IAE1C,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,iBAAiB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxC,GAAG,CAAC,iBAAiB,KAAK,CAAC,yBAAyB,EAAE,CAAC,CAAC;IACxD,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAE3C,OAAO,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QACxB,IAAI,IAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CACrC,SAAS,EACT,GAAG,OAAO,GAAG,gBAAgB,EAAE,EAC/B,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CACnC,CAAC;YACF,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;gBAClC,GAAG,CACD,kCAAkC,MAAM,KAAK;oBAC3C,eAAe,CAAC,IAAI,EAAE,2BAA2B,CAAC,CACrD,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAuB,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;YAC7D,IAAI,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/B,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,OAAO,GAAG,QAAQ,EAAE,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC;YAC9C,MAAM,OAAO,GACX,IAAI,CAAC,cAAc;gBACnB,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;gBACvC,IAAI,CAAC,cAAc,CAAC,OAAO;gBAC3B,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,KAAK,QAAQ;gBAC7C,CAAC,CAAE,IAAI,CAAC,cAAc,CAAC,OAAkC;gBACzD,CAAC,CAAC,SAAS,CAAC;YAChB,GAAG,CAAC,aAAa,CAAC,CAAC;YACnB,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;QACpE,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,GAAG,CAAC,uDAAuD,CAAC,CAAC;YAC7D,GAAG,CAAC,mCAAmC,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,GAAG,CAAC,8DAA8D,CAAC,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3D,GAAG,CACD,6BAA6B,eAAe,CAC1C,IAAI,EACJ,IAAI,CAAC,MAAM,KAAK,WAAW;gBACzB,CAAC,CAAC,4BAA4B;gBAC9B,CAAC,CAAC,2BAA2B,CAChC,EAAE,CACJ,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,mEAAmE,CAAC,CAAC;IACzE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAwB;IAExB,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7B,MAAM,OAAO,GAAyC,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,OAAO;YACP,aAAa;YACb,QAAQ,EAAE;gBACR,oBAAoB,UAAU,CAAC,UAAU,qCAAqC;aAC/E;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAEjD,0EAA0E;IAC1E,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,mBAAmB,CACjB,IAAI,CAAC,OAAO,EACZ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;IACxE,CAAC;IAED,uEAAuE;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7E,8EAA8E;IAC9E,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,mBAAmB,CACjB,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;QACF,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,YAAY,CAAC,kDAAkD,EAClF,+DAA+D,CAChE,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAE3C,6EAA6E;QAC7E,2EAA2E;QAC3E,yDAAyD;QACzD,MAAM,UAAU,GAAG,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC;QAE5C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,mBAAmB,CACjB,aAAa,EACb,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,yCAAyC,EAC1E,2CAA2C,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAC7E,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,sEAAsE,CACxG,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,EAAE,OAAQ,CAAC,CAAC;YACjD,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACxE,MAAM,KAAK,GAAG,MAAM,aAAa,CAC/B,OAAQ,EACR,OAAO,EACP,SAAS,EACT,GAAG,EACH,IAAI,CACL,CAAC;YAEF,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBACzB,wEAAwE;gBACxE,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC;gBAC3C,kBAAkB,CAChB,aAAa,EACb,IAAI,EACJ,WAAW,EACX,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,OAAO,EACb,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;gBACF,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,sEAAsE;gBACtE,sCAAsC;gBACtC,mBAAmB,CACjB,aAAa,EACb,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;gBACF,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,+DAA+D,EAChG,mBAAmB,sBAAsB,CAAC,OAAQ,CAAC,EAAE,CACtD,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,eAAe,CAAC,OAAmB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AAC/D,SAAS,UAAU,CAAC,UAAyB,EAAE,OAAe;IAC5D,uEAAuE;IACvE,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["/**\n * MCP-server registration + authentication for `@agent-native/skills`.\n *\n * This is a dependency-free port of the MCP-config-writing + device-code/OAuth\n * flow that lives in `@agent-native/core`'s `cli/connect.ts`. The skills package\n * ships standalone (no `@agent-native/core` dependency), so this module\n * re-implements just the registration surface against the shared on-disk\n * writers in `./mcp-config-writers.js`. It writes the SAME config and speaks the\n * SAME device-code/OAuth protocol as core.\n *\n * Two client families, exactly as in core:\n * - OAuth-capable (claude-code, claude-code-cli): get a URL-only HTTP MCP\n * entry (no bearer headers). The user authenticates in-host via standard\n * remote MCP OAuth: restart Claude Code, run /mcp, choose Authenticate.\n * - Device-code (codex, cowork): run the browser device-code flow against the\n * descriptor's hosted URL, then write the entry WITH the minted bearer token\n * + headers. Non-interactive (or no TTY) skips the flow and writes a\n * URL-only entry, surfacing the exact `agent-native connect <url> --token`\n * fallback command.\n *\n * Server contract (identical paths + JSON field names to core):\n * POST <hostedUrl>/_agent-native/mcp/connect/device/start (no auth)\n * body { client?, app? }\n * → { device_code, user_code, verification_uri,\n * verification_uri_complete, interval, expires_in }\n * POST <hostedUrl>/_agent-native/mcp/connect/device/poll (no auth)\n * body { device_code }\n * → { status: \"pending\" }\n * | { status: \"approved\", token, mcpUrl, serverName, mcpServerEntry }\n * | { status: \"expired\" } | { status: \"consumed\" }\n * | { status: \"error\" | \"not_found\", message? }\n *\n * Node-only. Node built-ins + global fetch only; no npm deps.\n */\n\nimport { ClientId, writeHttpEntryForClient } from \"./mcp-config-writers.js\";\n\nconst DEVICE_START_PATH = \"/_agent-native/mcp/connect/device/start\";\nconst DEVICE_POLL_PATH = \"/_agent-native/mcp/connect/device/poll\";\nconst MCP_PATH = \"/_agent-native/mcp\";\n\n/** OAuth-capable clients (in-host remote MCP OAuth, never a local bearer). */\nconst REMOTE_MCP_OAUTH_CLIENTS = new Set<ClientId>([\n \"claude-code\",\n \"claude-code-cli\",\n]);\n\n/** Identical to core: ask the deployed app to expose the full action catalog. */\nconst MCP_FULL_CATALOG_HEADER = \"X-Agent-Native-MCP-Full-Catalog\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Describes one MCP server to register. `serverName` is the canonical config\n * key; `aliases` are additional config keys that point at the same MCP URL\n * (e.g. `plan` + `agent-native-plans`). `hostedUrl` is the deployed app origin\n * the device-code flow authenticates against; `mcpUrl` is the resolved MCP\n * endpoint written into the config (defaults to `<hostedUrl>/_agent-native/mcp`\n * when only `hostedUrl` is supplied).\n */\nexport interface McpDescriptor {\n serverName: string;\n mcpUrl: string;\n aliases?: string[];\n authMode?: \"oauth\" | \"device\" | \"none\";\n hostedUrl?: string;\n}\n\nexport interface RegisterMcpOptions {\n descriptor: McpDescriptor;\n clients: ClientId[];\n scope: \"user\" | \"project\";\n baseDir: string;\n interactive: boolean;\n log?: (m: string) => void;\n deps?: {\n fetchImpl?: typeof fetch;\n now?: () => number;\n sleep?: (ms: number) => Promise<void>;\n };\n}\n\nexport interface RegisterMcpResult {\n written: { client: ClientId; file: string }[];\n authenticated: boolean;\n guidance: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Device-code protocol shapes (field names match core EXACTLY).\n// ---------------------------------------------------------------------------\n\ninterface DeviceStartResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n interval?: number;\n expires_in?: number;\n}\n\ninterface DevicePollResponse {\n status:\n | \"pending\"\n | \"approved\"\n | \"expired\"\n | \"consumed\"\n | \"error\"\n | \"not_found\";\n token?: string;\n mcpUrl?: string;\n serverName?: string;\n mcpServerEntry?: Record<string, unknown>;\n message?: string;\n error?: string;\n}\n\ninterface DeviceGrant {\n token?: string;\n mcpUrl: string;\n serverName: string;\n headers?: Record<string, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function supportsRemoteMcpOAuth(client: ClientId): boolean {\n return REMOTE_MCP_OAUTH_CLIENTS.has(client);\n}\n\nfunction realSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Trailing-slash-stripped origin+path for a hosted app URL. */\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve the MCP endpoint URL for a descriptor. Prefers an explicit `mcpUrl`,\n * otherwise derives `<hostedUrl>/_agent-native/mcp` (mirrors core's\n * `mcpUrlForBaseUrl`). Returns `undefined` when neither is usable.\n */\nfunction resolveMcpUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n return descriptor.mcpUrl.trim();\n }\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n const base = stripTrailingSlash(descriptor.hostedUrl.trim());\n return `${base}${MCP_PATH}`;\n }\n return undefined;\n}\n\n/** Base (origin) URL of the deployed app the device flow runs against. */\nfunction resolveBaseUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n return stripTrailingSlash(descriptor.hostedUrl.trim());\n }\n // Fall back to stripping the MCP path off an explicit mcpUrl.\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n const trimmed = stripTrailingSlash(descriptor.mcpUrl.trim());\n if (trimmed.endsWith(MCP_PATH)) {\n return trimmed.slice(0, -MCP_PATH.length);\n }\n }\n return undefined;\n}\n\n/** All config keys to register: the canonical name plus any aliases (deduped). */\nfunction configKeys(descriptor: McpDescriptor): string[] {\n const keys: string[] = [descriptor.serverName];\n for (const alias of descriptor.aliases ?? []) {\n if (alias && alias !== descriptor.serverName && !keys.includes(alias)) {\n keys.push(alias);\n }\n }\n return keys;\n}\n\n/** Always tag bearer-bearing entries so the client sees the full catalog. */\nfunction withFullCatalogHeader(\n headers: Record<string, string> | undefined,\n): Record<string, string> {\n return { ...(headers ?? {}), [MCP_FULL_CATALOG_HEADER]: \"1\" };\n}\n\nfunction responseMessage(json: any, fallback: string): string {\n const message =\n typeof json?.message === \"string\"\n ? json.message\n : typeof json?.error === \"string\"\n ? json.error\n : \"\";\n return message.trim() || fallback;\n}\n\nasync function postJson(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<{ status: number; json: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body ?? {}),\n signal: controller.signal,\n });\n let json: any = null;\n try {\n json = await response.json();\n } catch {\n json = null;\n }\n return { status: response.status, json };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * The exact no-browser fallback command core prints. Surfaced as guidance when\n * a device-code client is asked to register non-interactively.\n */\nfunction fallbackConnectCommand(baseUrl: string): string {\n return `npx @agent-native/core@latest connect ${baseUrl} --token <token>`;\n}\n\n/** Write a URL-only entry (no bearer) for every config key, collecting files. */\nfunction writeUrlOnlyEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n undefined,\n baseDir,\n scope,\n undefined,\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\n/** Write a token+headers entry for every config key, collecting files. */\nfunction writeAuthedEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n token: string | undefined,\n headers: Record<string, string> | undefined,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n token,\n baseDir,\n scope,\n withFullCatalogHeader(headers),\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Device-code flow (dependency-free port of core's runDeviceFlow)\n// ---------------------------------------------------------------------------\n\n/**\n * Run the device-code flow against `baseUrl` and return the approved grant, or\n * `null` (after logging a clear message) on expiry/consumed/error/timeout. Same\n * state machine and field handling as core; the spinner/browser-open are\n * dropped since this runs inside a non-interactive installer context.\n */\nasync function runDeviceFlow(\n baseUrl: string,\n appSlug: string,\n clientArg: string,\n log: (m: string) => void,\n deps: RegisterMcpOptions[\"deps\"] = {},\n): Promise<DeviceGrant | null> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? realSleep;\n const now = deps.now ?? (() => Date.now());\n\n let start: DeviceStartResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_START_PATH}`,\n { client: clientArg, app: appSlug },\n );\n if (status < 200 || status >= 300 || !json?.device_code) {\n log(\n ` Could not start the connect flow on ${baseUrl} (HTTP ${status}). ` +\n `Is this an agent-native app, and is it deployed with the connect ` +\n `endpoint enabled?`,\n );\n return null;\n }\n start = json as DeviceStartResponse;\n } catch (err: any) {\n log(\n ` Could not reach ${baseUrl} (${err?.message ?? err}). ` +\n `Check the URL and your network.`,\n );\n return null;\n }\n\n const interval = Math.max(1, Number(start.interval) || 5);\n const expiresIn = Math.max(interval, Number(start.expires_in) || 600);\n const deadline = now() + expiresIn * 1000;\n\n log(\"\");\n log(` Connecting to ${baseUrl}`);\n log(\"\");\n log(` Your code: ${start.user_code}`);\n log(` Open: ${start.verification_uri_complete}`);\n log(\"\");\n log(\" Approve in the browser to finish.\");\n\n while (now() < deadline) {\n let poll: DevicePollResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_POLL_PATH}`,\n { device_code: start.device_code },\n );\n if (status < 200 || status >= 300) {\n log(\n ` Connect polling failed (HTTP ${status}): ` +\n responseMessage(json, \"server returned an error.\"),\n );\n return null;\n }\n poll = (json ?? { status: \"pending\" }) as DevicePollResponse;\n } catch {\n // Transient network error — keep polling until the deadline.\n poll = { status: \"pending\" };\n }\n\n if (poll.status === \"approved\") {\n const token = poll.token ?? \"\";\n const mcpUrl = poll.mcpUrl ?? `${baseUrl}${MCP_PATH}`;\n const serverName = poll.serverName ?? appSlug;\n const headers =\n poll.mcpServerEntry &&\n typeof poll.mcpServerEntry === \"object\" &&\n poll.mcpServerEntry.headers &&\n typeof poll.mcpServerEntry.headers === \"object\"\n ? (poll.mcpServerEntry.headers as Record<string, string>)\n : undefined;\n log(\" Approved.\");\n return { token: token || undefined, mcpUrl, serverName, headers };\n }\n if (poll.status === \"expired\") {\n log(\" The connect request expired before it was approved.\");\n log(\" Run the command again to retry.\");\n return null;\n }\n if (poll.status === \"consumed\") {\n log(\" This connect code was already used. Run the command again.\");\n return null;\n }\n if (poll.status === \"error\" || poll.status === \"not_found\") {\n log(\n ` Connect polling failed: ${responseMessage(\n poll,\n poll.status === \"not_found\"\n ? \"device code was not found.\"\n : \"server returned an error.\",\n )}`,\n );\n return null;\n }\n\n await sleep(interval * 1000);\n }\n\n log(\" Timed out waiting for approval. Run the command again to retry.\");\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Register an MCP server (plus aliases) into the requested client configs,\n * authenticating device-code clients via the browser flow when interactive.\n *\n * Idempotent: re-running replaces the same named entries. Never throws on a\n * single client/key failing — failures are collected into `guidance`.\n */\nexport async function registerMcpServer(\n opts: RegisterMcpOptions,\n): Promise<RegisterMcpResult> {\n const { descriptor, scope, baseDir, interactive } = opts;\n const log = opts.log ?? (() => {});\n const deps = opts.deps ?? {};\n\n const written: { client: ClientId; file: string }[] = [];\n const guidance: string[] = [];\n const errors: string[] = [];\n let authenticated = false;\n\n const keys = configKeys(descriptor);\n const mcpUrl = resolveMcpUrl(descriptor);\n if (!mcpUrl) {\n return {\n written,\n authenticated,\n guidance: [\n `Cannot register \"${descriptor.serverName}\": no mcpUrl or hostedUrl supplied.`,\n ],\n };\n }\n\n const authMode = descriptor.authMode ?? \"device\";\n\n // authMode \"none\" (e.g. context-xray): URL-only for ALL clients, no auth.\n if (authMode === \"none\") {\n writeUrlOnlyEntries(\n opts.clients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n return { written, authenticated, guidance: [...guidance, ...errors] };\n }\n\n // Split into OAuth-capable and device-code clients, exactly like core.\n const oauthClients = opts.clients.filter((c) => supportsRemoteMcpOAuth(c));\n const deviceClients = opts.clients.filter((c) => !supportsRemoteMcpOAuth(c));\n\n // OAuth clients always get URL-only entries (in-host OAuth, no local bearer).\n if (oauthClients.length > 0) {\n writeUrlOnlyEntries(\n oauthClients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n guidance.push(\n `${describeClients(oauthClients)}: wrote URL-only MCP config (no bearer headers).`,\n \"Next: restart Claude Code, run /mcp, and choose Authenticate.\",\n );\n }\n\n // Device-code clients.\n if (deviceClients.length > 0) {\n const baseUrl = resolveBaseUrl(descriptor);\n\n // We only reach here for authMode \"oauth\"/\"device\" (authMode \"none\" returned\n // earlier). Run the flow only when interactive AND we have a hosted URL to\n // authenticate against; otherwise fall back to URL-only.\n const canRunFlow = interactive && !!baseUrl;\n\n if (!canRunFlow) {\n writeUrlOnlyEntries(\n deviceClients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n if (baseUrl) {\n guidance.push(\n `${describeClients(deviceClients)}: wrote URL-only MCP config (no token).`,\n `To authenticate non-interactively, run: ${fallbackConnectCommand(baseUrl)}`,\n );\n } else {\n guidance.push(\n `${describeClients(deviceClients)}: wrote URL-only MCP config (no hosted URL to authenticate against).`,\n );\n }\n } else {\n const appSlug = appSlugFor(descriptor, baseUrl!);\n const clientArg = deviceClients.length === 1 ? deviceClients[0] : \"all\";\n const grant = await runDeviceFlow(\n baseUrl!,\n appSlug,\n clientArg,\n log,\n deps,\n );\n\n if (grant && grant.token) {\n // Write authed entries; honour the server's resolved mcpUrl when given.\n const resolvedUrl = grant.mcpUrl || mcpUrl;\n writeAuthedEntries(\n deviceClients,\n keys,\n resolvedUrl,\n grant.token,\n grant.headers,\n scope,\n baseDir,\n written,\n errors,\n );\n authenticated = true;\n } else {\n // Flow failed (or approved with no token) — fall back to URL-only and\n // surface the exact recovery command.\n writeUrlOnlyEntries(\n deviceClients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n guidance.push(\n `${describeClients(deviceClients)}: authentication did not complete; wrote URL-only MCP config.`,\n `To finish, run: ${fallbackConnectCommand(baseUrl!)}`,\n );\n }\n }\n }\n\n return { written, authenticated, guidance: [...guidance, ...errors] };\n}\n\nfunction describeClients(clients: ClientId[]): string {\n return clients.join(\", \");\n}\n\n/** Derive the `app` slug the device-start endpoint expects. */\nfunction appSlugFor(descriptor: McpDescriptor, baseUrl: string): string {\n // Prefer the descriptor's server name without the agent-native prefix.\n const name = descriptor.serverName.replace(/^agent-native-/, \"\");\n if (name) return name;\n try {\n const host = new URL(baseUrl).hostname;\n const first = host.split(\".\")[0];\n return first && first !== \"www\" ? first : \"app\";\n } catch {\n return \"app\";\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type CliTelemetry } from "./telemetry.js";
1
2
  export type SkillClient = "codex" | "claude-code";
2
3
  export type SkillScope = "project" | "user";
3
4
  export interface SkillEntry {
@@ -19,6 +20,21 @@ export interface InstallSkillsOptions {
19
20
  force?: boolean;
20
21
  log?: (message: string) => void;
21
22
  isInteractive?: () => boolean;
23
+ telemetry?: CliTelemetry;
24
+ /**
25
+ * Register the hosted MCP server for app-backed skills (e.g. visual-plan /
26
+ * visual-recap → the Agent-Native Plan MCP). Defaults to `true`; pass
27
+ * `false` (CLI `--no-mcp`) to install the skill files only.
28
+ */
29
+ mcp?: boolean;
30
+ }
31
+ export interface InstalledMcpServer {
32
+ serverName: string;
33
+ mcpUrl: string;
34
+ clients: SkillClient[];
35
+ files: string[];
36
+ authenticated: boolean;
37
+ guidance: string[];
22
38
  }
23
39
  export interface InstallSkillsResult {
24
40
  source: string;
@@ -28,6 +44,7 @@ export interface InstallSkillsResult {
28
44
  written: string[];
29
45
  instructionFiles: string[];
30
46
  githubActionPath?: string;
47
+ mcpServers: InstalledMcpServer[];
31
48
  dryRun: boolean;
32
49
  }
33
50
  interface ParsedArgs {
@@ -37,6 +54,7 @@ interface ParsedArgs {
37
54
  skillNames: string[];
38
55
  clients: SkillClient[];
39
56
  scope: SkillScope;
57
+ scopeExplicit: boolean;
40
58
  yes: boolean;
41
59
  dryRun: boolean;
42
60
  printJson: boolean;
@@ -45,6 +63,7 @@ interface ParsedArgs {
45
63
  withGithubAction: boolean;
46
64
  force: boolean;
47
65
  baseDir?: string;
66
+ mcp: boolean;
48
67
  }
49
68
  export declare function parseSkillsCliArgs(argv: string[]): ParsedArgs;
50
69
  export declare function runSkillsCli(argv: string[], options?: Pick<InstallSkillsOptions, "log" | "isInteractive" | "baseDir">): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,aAAa,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAkCD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAyE7D;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,KAAK,GAAG,eAAe,GAAG,SAAS,CAAM,GAC5E,OAAO,CAAC,IAAI,CAAC,CAkEf;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA4D9B;AAseD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4,6 +4,10 @@ import fs from "node:fs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
  import readline from "node:readline/promises";
7
+ import { fileURLToPath } from "node:url";
8
+ import { resolveAppForSkill } from "./built-in-apps.js";
9
+ import { registerMcpServer } from "./connect.js";
10
+ import { createCliTelemetry } from "./telemetry.js";
7
11
  const HELP = `@agent-native/skills
8
12
 
9
13
  Usage:
@@ -21,10 +25,15 @@ Options:
21
25
  --instructions-file <path> File to receive managed instructions (repeatable)
22
26
  --with-github-action Add .github/workflows/pr-visual-recap.yml when visual-recap is installed
23
27
  --force Overwrite a different existing PR Visual Recap workflow
28
+ --no-mcp Install skill files only; skip registering the app's MCP server
24
29
  -y, --yes Use defaults in non-interactive mode
25
30
  --dry-run Print intended writes without changing files
26
31
  --json Print the result as JSON
27
32
 
33
+ App-backed skills (visual-plan, visual-recap, assets, design-exploration)
34
+ register their hosted MCP server in your agent config by default so the agent
35
+ can actually use them. Use --no-mcp to skip that and copy the files only.
36
+
28
37
  Examples:
29
38
  npx @agent-native/skills add
30
39
  npx @agent-native/skills add --skill quick-recap
@@ -71,16 +80,22 @@ export function parseSkillsCliArgs(argv) {
71
80
  out.clients.push(...normalizeClients(value));
72
81
  else if ((value = eat("-a")) !== undefined)
73
82
  out.clients.push(...normalizeClients(value));
74
- else if ((value = eat("--scope")) !== undefined)
83
+ else if ((value = eat("--scope")) !== undefined) {
75
84
  out.scope = parseScope(value);
85
+ out.scopeExplicit = true;
86
+ }
76
87
  else if ((value = eat("--instructions-file")) !== undefined)
77
88
  out.instructionFiles.push(value);
78
89
  else if ((value = eat("--cwd")) !== undefined)
79
90
  out.baseDir = value;
80
- else if (arg === "-g" || arg === "--global")
91
+ else if (arg === "-g" || arg === "--global") {
81
92
  out.scope = "user";
82
- else if (arg === "--project")
93
+ out.scopeExplicit = true;
94
+ }
95
+ else if (arg === "--project") {
83
96
  out.scope = "project";
97
+ out.scopeExplicit = true;
98
+ }
84
99
  else if (arg === "--copy") {
85
100
  // Compatibility with the open `skills` CLI. This installer always copies.
86
101
  out.copySource = true;
@@ -99,6 +114,10 @@ export function parseSkillsCliArgs(argv) {
99
114
  out.withGithubAction = true;
100
115
  else if (arg === "--force")
101
116
  out.force = true;
117
+ else if (arg === "--no-mcp")
118
+ out.mcp = false;
119
+ else if (arg === "--mcp")
120
+ out.mcp = true;
102
121
  else if (arg.startsWith("-"))
103
122
  throw new Error(`Unknown option: ${arg}`);
104
123
  else if (!out.source)
@@ -117,65 +136,183 @@ export function parseSkillsCliArgs(argv) {
117
136
  out.instructionFiles = unique(out.instructionFiles);
118
137
  return out;
119
138
  }
139
+ /**
140
+ * Translate this package's parsed args into the argv shape `@agent-native/core`
141
+ * skills expects. Core takes a single positional target + compatible flags; we
142
+ * forward one explicit skill as that target and let core's interactive picker
143
+ * handle 0-or-many selections.
144
+ */
145
+ function toCoreSkillsArgv(parsed) {
146
+ const out = [parsed.command];
147
+ if (parsed.command !== "add")
148
+ return out;
149
+ if (parsed.skillNames.length === 1)
150
+ out.push(parsed.skillNames[0]);
151
+ else if (parsed.copySource && parsed.source)
152
+ out.push(parsed.source);
153
+ if (parsed.clients.length)
154
+ out.push("--client", parsed.clients.join(","));
155
+ if (parsed.scopeExplicit)
156
+ out.push("--scope", parsed.scope);
157
+ if (parsed.yes)
158
+ out.push("--yes");
159
+ if (parsed.dryRun)
160
+ out.push("--dry-run");
161
+ if (parsed.printJson)
162
+ out.push("--json");
163
+ if (parsed.withGithubAction)
164
+ out.push("--with-github-action");
165
+ if (parsed.force)
166
+ out.push("--force");
167
+ if (parsed.mcp === false)
168
+ out.push("--no-mcp");
169
+ if (parsed.updateInstructions === true)
170
+ out.push("--update-instructions");
171
+ if (parsed.updateInstructions === false)
172
+ out.push("--no-update-instructions");
173
+ return out;
174
+ }
120
175
  export async function runSkillsCli(argv, options = {}) {
121
176
  const parsed = parseSkillsCliArgs(argv);
122
- if (parsed.command === "help") {
123
- process.stdout.write(`${HELP}\n`);
124
- return;
177
+ // PIVOT: `@agent-native/skills` delegates its install/list flow to
178
+ // `@agent-native/core`'s clack-based installer so both CLIs share ONE codebase
179
+ // and UX. App-backed skills (visual-plan/visual-recap/assets/design-exploration/
180
+ // context-xray) and the interactive picker go through core. Plain BuilderIO
181
+ // skills (efficient-fable, quick-recap, …) aren't known to core, so an explicit
182
+ // plain `--skill` falls through to this package's own headless installer.
183
+ // AGENT_NATIVE_SKILLS_DIRECT=1 (set when core delegates a plain repo back to us)
184
+ // always forces the direct path and breaks the skills → core → skills loop.
185
+ if (process.env.AGENT_NATIVE_SKILLS_DIRECT !== "1") {
186
+ const appOnly = parsed.skillNames.length === 0 ||
187
+ parsed.skillNames.every((name) => resolveAppForSkill(name) !== undefined);
188
+ if (parsed.command === "list" || (parsed.command === "add" && appOnly)) {
189
+ const { runSkills } = await import("@agent-native/core/cli/skills");
190
+ await runSkills(toCoreSkillsArgv(parsed), {
191
+ isInteractive: options.isInteractive,
192
+ baseDir: parsed.baseDir ?? options.baseDir,
193
+ });
194
+ return;
195
+ }
125
196
  }
126
- const skillSource = parsed.source ?? DEFAULT_SKILLS_SOURCE;
127
- if (parsed.command === "list") {
128
- const source = await materializeSource(skillSource);
129
- try {
130
- const skills = discoverSkills(source.root);
131
- if (parsed.printJson) {
132
- process.stdout.write(`${JSON.stringify(skills, null, 2)}\n`);
197
+ const startedAt = Date.now();
198
+ const telemetry = createCliTelemetry({
199
+ cli: "skills-installer",
200
+ cliVersion: readCliVersion(),
201
+ command: parsed.command,
202
+ interactive: cliInteractive(parsed, options),
203
+ });
204
+ try {
205
+ if (parsed.command === "help") {
206
+ process.stdout.write(`${HELP}\n`);
207
+ return;
208
+ }
209
+ telemetry.track("skills_cli started");
210
+ const skillSource = parsed.source ?? DEFAULT_SKILLS_SOURCE;
211
+ if (parsed.command === "list") {
212
+ const source = await materializeSource(skillSource);
213
+ try {
214
+ const skills = discoverSkills(source.root);
215
+ telemetry.track("skills_cli skills listed", {
216
+ availableCount: skills.length,
217
+ available: skills.map((skill) => skill.name).join(","),
218
+ });
219
+ if (parsed.printJson) {
220
+ process.stdout.write(`${JSON.stringify(skills, null, 2)}\n`);
221
+ return;
222
+ }
223
+ for (const skill of skills) {
224
+ process.stdout.write(`${skill.name}${skill.description ? ` - ${skill.description}` : ""}\n`);
225
+ }
133
226
  return;
134
227
  }
135
- for (const skill of skills) {
136
- process.stdout.write(`${skill.name}${skill.description ? ` - ${skill.description}` : ""}\n`);
228
+ finally {
229
+ source.cleanup?.();
137
230
  }
138
- return;
139
231
  }
140
- finally {
141
- source.cleanup?.();
232
+ const result = await installSkills({
233
+ source: skillSource,
234
+ skillNames: parsed.skillNames,
235
+ clients: parsed.clients,
236
+ // Leave scope undefined unless the user passed --scope/-g/--project so the
237
+ // installer can prompt for it interactively.
238
+ scope: parsed.scopeExplicit ? parsed.scope : undefined,
239
+ baseDir: parsed.baseDir ?? options.baseDir,
240
+ yes: parsed.yes,
241
+ dryRun: parsed.dryRun,
242
+ updateInstructions: parsed.updateInstructions,
243
+ instructionFiles: parsed.instructionFiles,
244
+ withGithubAction: parsed.withGithubAction,
245
+ force: parsed.force,
246
+ log: parsed.printJson ? undefined : options.log,
247
+ isInteractive: options.isInteractive,
248
+ telemetry,
249
+ mcp: parsed.mcp,
250
+ });
251
+ telemetry.track("skills_cli completed", {
252
+ skills: result.skills.join(","),
253
+ clients: result.clients.join(","),
254
+ scope: result.scope,
255
+ dryRun: result.dryRun,
256
+ durationMs: Date.now() - startedAt,
257
+ });
258
+ if (parsed.printJson) {
259
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
260
+ return;
142
261
  }
262
+ const verb = parsed.dryRun ? "Would install" : "Installed";
263
+ process.stdout.write([
264
+ `${verb} ${result.skills.join(", ")} for ${result.clients.join(", ")} (${result.scope}).`,
265
+ result.written.length
266
+ ? `Skill files: ${result.written.join(", ")}`
267
+ : "",
268
+ result.instructionFiles.length
269
+ ? `Managed instructions: ${result.instructionFiles.join(", ")}`
270
+ : "",
271
+ result.githubActionPath
272
+ ? `PR Visual Recap workflow: ${result.githubActionPath}`
273
+ : "",
274
+ ...result.mcpServers.flatMap((server) => [
275
+ `MCP server "${server.serverName}" ${parsed.dryRun ? "would be registered" : "registered"} for ${server.clients.join(", ")}${server.files.length ? `:\n ${server.files.join("\n ")}` : ""}`,
276
+ ...server.guidance.map((line) => ` ${line}`),
277
+ ]),
278
+ parsed.dryRun
279
+ ? ""
280
+ : "Restart or reload selected agent clients if needed.",
281
+ ]
282
+ .filter(Boolean)
283
+ .join("\n") + "\n");
284
+ }
285
+ catch (error) {
286
+ telemetry.track("skills_cli failed", {
287
+ command: parsed.command,
288
+ error: error instanceof Error ? error.message : String(error),
289
+ durationMs: Date.now() - startedAt,
290
+ });
291
+ throw error;
143
292
  }
144
- const result = await installSkills({
145
- source: skillSource,
146
- skillNames: parsed.skillNames,
147
- clients: parsed.clients,
148
- scope: parsed.scope,
149
- baseDir: parsed.baseDir ?? options.baseDir,
150
- yes: parsed.yes,
151
- dryRun: parsed.dryRun,
152
- updateInstructions: parsed.updateInstructions,
153
- instructionFiles: parsed.instructionFiles,
154
- withGithubAction: parsed.withGithubAction,
155
- force: parsed.force,
156
- log: parsed.printJson ? undefined : options.log,
157
- isInteractive: options.isInteractive,
158
- });
159
- if (parsed.printJson) {
160
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
161
- return;
162
- }
163
- const verb = parsed.dryRun ? "Would install" : "Installed";
164
- process.stdout.write([
165
- `${verb} ${result.skills.join(", ")} for ${result.clients.join(", ")} (${result.scope}).`,
166
- result.written.length ? `Skill files: ${result.written.join(", ")}` : "",
167
- result.instructionFiles.length
168
- ? `Managed instructions: ${result.instructionFiles.join(", ")}`
169
- : "",
170
- result.githubActionPath
171
- ? `PR Visual Recap workflow: ${result.githubActionPath}`
172
- : "",
173
- parsed.dryRun
174
- ? ""
175
- : "Restart or reload selected agent clients if needed.",
176
- ]
177
- .filter(Boolean)
178
- .join("\n") + "\n");
293
+ finally {
294
+ await telemetry.flush();
295
+ }
296
+ }
297
+ function readCliVersion() {
298
+ try {
299
+ const here = path.dirname(fileURLToPath(import.meta.url));
300
+ // dist/index.js → ../package.json
301
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(here, "../package.json"), "utf8"));
302
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
303
+ }
304
+ catch {
305
+ return "unknown";
306
+ }
307
+ }
308
+ function cliInteractive(parsed, options) {
309
+ if (parsed.yes)
310
+ return false;
311
+ if (options.isInteractive)
312
+ return options.isInteractive();
313
+ if (process.env.CI === "true")
314
+ return false;
315
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
179
316
  }
180
317
  export async function installSkills(options) {
181
318
  const baseDir = path.resolve(options.baseDir ?? process.cwd());
@@ -187,9 +324,30 @@ export async function installSkills(options) {
187
324
  if (entries.length === 0) {
188
325
  throw new Error(`No skills found in ${sourceInput}. Expected skills/*/SKILL.md.`);
189
326
  }
327
+ // Fire the "skills prompted" step only when an interactive chooser will
328
+ // actually be shown (mirrors resolveSelectedSkills's prompt condition), so
329
+ // the funnel distinguishes "saw the picker" from "passed --skill".
330
+ const preselected = (options.skillNames ?? []).length > 0;
331
+ if (isInteractive(options) && !options.yes && !preselected) {
332
+ options.telemetry?.track("skills_cli skills prompted", {
333
+ availableCount: entries.length,
334
+ available: entries.map((entry) => entry.name).join(","),
335
+ });
336
+ }
190
337
  const selected = await resolveSelectedSkills(entries, options);
338
+ options.telemetry?.track("skills_cli skills selected", {
339
+ selected: selected.map((skill) => skill.name).join(","),
340
+ selectedCount: selected.length,
341
+ selectedAll: selected.length === entries.length,
342
+ preselected,
343
+ });
191
344
  const clients = await resolveSelectedClients(options);
192
- const scope = options.scope ?? "user";
345
+ options.telemetry?.track("skills_cli clients selected", {
346
+ clients: clients.join(","),
347
+ clientCount: clients.length,
348
+ });
349
+ const scope = await resolveSelectedScope(options);
350
+ options.telemetry?.track("skills_cli scope selected", { scope });
193
351
  const written = [];
194
352
  for (const client of clients) {
195
353
  const root = installRootForClient(client, scope, baseDir);
@@ -203,12 +361,81 @@ export async function installSkills(options) {
203
361
  }
204
362
  }
205
363
  }
364
+ options.telemetry?.track("skills_cli install completed", {
365
+ skills: selected.map((skill) => skill.name).join(","),
366
+ clients: clients.join(","),
367
+ scope,
368
+ writtenCount: written.length,
369
+ dryRun: Boolean(options.dryRun),
370
+ });
206
371
  const instructionFiles = await maybeUpdateInstructions(selected.map((skill) => skill.name), baseDir, options);
372
+ if (instructionFiles.length) {
373
+ options.telemetry?.track("skills_cli instructions updated", {
374
+ fileCount: instructionFiles.length,
375
+ });
376
+ }
207
377
  const githubActionPath = selected.some((skill) => skill.name === "visual-recap") &&
208
378
  (options.withGithubAction ||
209
379
  (await shouldPromptGithubAction(options, baseDir)))
210
380
  ? writePrVisualRecapWorkflow(baseDir, options)
211
381
  : undefined;
382
+ if (githubActionPath) {
383
+ options.telemetry?.track("skills_cli github action added");
384
+ }
385
+ // Register the hosted MCP server for app-backed skills (visual-plan /
386
+ // visual-recap → Agent-Native Plan, assets, design-exploration) so the
387
+ // agent can actually call them — not just read the SKILL.md. On by
388
+ // default; `--no-mcp` installs the skill files only. One registration per
389
+ // app, so visual-plan + visual-recap share a single "plan" server.
390
+ const mcpServers = [];
391
+ if (options.mcp !== false) {
392
+ const mcpClients = clients.map((client) => client === "claude-code" ? "claude-code" : "codex");
393
+ const seenApps = new Set();
394
+ for (const skill of selected) {
395
+ const app = resolveAppForSkill(skill.name);
396
+ if (!app || seenApps.has(app.appId))
397
+ continue;
398
+ seenApps.add(app.appId);
399
+ if (options.dryRun) {
400
+ mcpServers.push({
401
+ serverName: app.serverName,
402
+ mcpUrl: app.mcpUrl,
403
+ clients,
404
+ files: [],
405
+ authenticated: false,
406
+ guidance: [],
407
+ });
408
+ continue;
409
+ }
410
+ const registration = await registerMcpServer({
411
+ descriptor: {
412
+ serverName: app.serverName,
413
+ mcpUrl: app.mcpUrl,
414
+ aliases: app.aliases,
415
+ authMode: app.authMode,
416
+ hostedUrl: app.hostedUrl,
417
+ },
418
+ clients: mcpClients,
419
+ scope,
420
+ baseDir,
421
+ interactive: isInteractive(options),
422
+ log,
423
+ });
424
+ mcpServers.push({
425
+ serverName: app.serverName,
426
+ mcpUrl: app.mcpUrl,
427
+ clients,
428
+ files: [...new Set(registration.written.map((entry) => entry.file))],
429
+ authenticated: registration.authenticated,
430
+ guidance: registration.guidance,
431
+ });
432
+ options.telemetry?.track("skills_cli mcp registered", {
433
+ serverName: app.serverName,
434
+ clients: clients.join(","),
435
+ authenticated: registration.authenticated,
436
+ });
437
+ }
438
+ }
212
439
  log(`Resolved ${selected.length} skill${selected.length === 1 ? "" : "s"} from ${source.root}.`);
213
440
  return {
214
441
  source: source.root,
@@ -218,6 +445,7 @@ export async function installSkills(options) {
218
445
  written,
219
446
  instructionFiles,
220
447
  githubActionPath,
448
+ mcpServers,
221
449
  dryRun: Boolean(options.dryRun),
222
450
  };
223
451
  }
@@ -232,12 +460,14 @@ function defaultArgs(command) {
232
460
  skillNames: [],
233
461
  clients: [],
234
462
  scope: "user",
463
+ scopeExplicit: false,
235
464
  yes: false,
236
465
  dryRun: false,
237
466
  printJson: false,
238
467
  instructionFiles: [],
239
468
  withGithubAction: false,
240
469
  force: false,
470
+ mcp: true,
241
471
  };
242
472
  }
243
473
  function parseScope(value) {
@@ -312,6 +542,22 @@ async function resolveSelectedSkills(entries, options) {
312
542
  skillNames: selectedNames,
313
543
  });
314
544
  }
545
+ async function resolveSelectedScope(options) {
546
+ if (options.scope)
547
+ return options.scope;
548
+ if (!isInteractive(options) || options.yes)
549
+ return "user";
550
+ const answer = await promptLine([
551
+ "Where do you want to install these skills?",
552
+ " 1. project - this repo only (.agents / .claude in the current directory)",
553
+ " 2. user - your home directory, available across all projects",
554
+ "Enter project or user [project]: ",
555
+ ].join("\n"));
556
+ const trimmed = answer.trim().toLowerCase();
557
+ if (trimmed === "2" || trimmed === "user" || trimmed === "u")
558
+ return "user";
559
+ return "project";
560
+ }
315
561
  async function resolveSelectedClients(options) {
316
562
  const requested = unique(options.clients ?? []);
317
563
  if (requested.length > 0)