@ekanos/cli 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +25 -8
  2. package/dist/agents-api.d.ts +11 -2
  3. package/dist/agents-api.js +39 -3
  4. package/dist/agents-api.js.map +1 -1
  5. package/dist/apps-api.d.ts +3 -2
  6. package/dist/apps-api.js +3 -7
  7. package/dist/apps-api.js.map +1 -1
  8. package/dist/auth/ekanos-api.d.ts +16 -2
  9. package/dist/auth/ekanos-api.js +101 -15
  10. package/dist/auth/ekanos-api.js.map +1 -1
  11. package/dist/auth/host-trust.d.ts +46 -0
  12. package/dist/auth/host-trust.js +79 -0
  13. package/dist/auth/host-trust.js.map +1 -0
  14. package/dist/auth/session.d.ts +10 -1
  15. package/dist/auth/session.js +28 -28
  16. package/dist/auth/session.js.map +1 -1
  17. package/dist/commands/agents-edit.d.ts +6 -2
  18. package/dist/commands/agents-edit.js +57 -26
  19. package/dist/commands/agents-edit.js.map +1 -1
  20. package/dist/commands/agents.d.ts +13 -2
  21. package/dist/commands/agents.js +148 -36
  22. package/dist/commands/agents.js.map +1 -1
  23. package/dist/commands/apps.d.ts +15 -4
  24. package/dist/commands/apps.js +133 -51
  25. package/dist/commands/apps.js.map +1 -1
  26. package/dist/commands/catalog.js +7 -6
  27. package/dist/commands/catalog.js.map +1 -1
  28. package/dist/commands/knowledge.d.ts +56 -0
  29. package/dist/commands/knowledge.js +456 -0
  30. package/dist/commands/knowledge.js.map +1 -0
  31. package/dist/commands/login.d.ts +4 -0
  32. package/dist/commands/login.js +30 -2
  33. package/dist/commands/login.js.map +1 -1
  34. package/dist/commands/logout.d.ts +9 -1
  35. package/dist/commands/logout.js +56 -7
  36. package/dist/commands/logout.js.map +1 -1
  37. package/dist/commands/publish.js +3 -3
  38. package/dist/commands/publish.js.map +1 -1
  39. package/dist/commands/reviewers.d.ts +2 -0
  40. package/dist/commands/reviewers.js +7 -3
  41. package/dist/commands/reviewers.js.map +1 -1
  42. package/dist/commands/routes.d.ts +2 -0
  43. package/dist/commands/routes.js +42 -9
  44. package/dist/commands/routes.js.map +1 -1
  45. package/dist/commands/runs.d.ts +13 -2
  46. package/dist/commands/runs.js +96 -15
  47. package/dist/commands/runs.js.map +1 -1
  48. package/dist/commands/scope-notice.d.ts +21 -0
  49. package/dist/commands/scope-notice.js +35 -0
  50. package/dist/commands/scope-notice.js.map +1 -0
  51. package/dist/commands/skills.d.ts +7 -1
  52. package/dist/commands/skills.js +80 -24
  53. package/dist/commands/skills.js.map +1 -1
  54. package/dist/commands/sources.d.ts +4 -0
  55. package/dist/commands/sources.js +233 -5
  56. package/dist/commands/sources.js.map +1 -1
  57. package/dist/commands/status.js +5 -4
  58. package/dist/commands/status.js.map +1 -1
  59. package/dist/commands/team-agent-readiness.d.ts +59 -0
  60. package/dist/commands/team-agent-readiness.js +341 -0
  61. package/dist/commands/team-agent-readiness.js.map +1 -0
  62. package/dist/commands/team-agents-agents.d.ts +24 -3
  63. package/dist/commands/team-agents-agents.js +336 -35
  64. package/dist/commands/team-agents-agents.js.map +1 -1
  65. package/dist/commands/team-agents-mcp.js +32 -3
  66. package/dist/commands/team-agents-mcp.js.map +1 -1
  67. package/dist/commands/team-agents-triggers.js +230 -54
  68. package/dist/commands/team-agents-triggers.js.map +1 -1
  69. package/dist/commands/team-agents.d.ts +3 -1
  70. package/dist/commands/team-agents.js +27 -7
  71. package/dist/commands/team-agents.js.map +1 -1
  72. package/dist/commands/teams-channel-install.d.ts +24 -0
  73. package/dist/commands/teams-channel-install.js +94 -0
  74. package/dist/commands/teams-channel-install.js.map +1 -0
  75. package/dist/commands/teams-connect.d.ts +66 -0
  76. package/dist/commands/teams-connect.js +397 -0
  77. package/dist/commands/teams-connect.js.map +1 -0
  78. package/dist/commands/teams-events.d.ts +12 -0
  79. package/dist/commands/teams-events.js +138 -0
  80. package/dist/commands/teams-events.js.map +1 -0
  81. package/dist/commands/teams-onboard.d.ts +16 -5
  82. package/dist/commands/teams-onboard.js +61 -36
  83. package/dist/commands/teams-onboard.js.map +1 -1
  84. package/dist/commands/teams-overview.d.ts +11 -0
  85. package/dist/commands/teams-overview.js +160 -0
  86. package/dist/commands/teams-overview.js.map +1 -0
  87. package/dist/commands/teams-scope.d.ts +10 -0
  88. package/dist/commands/teams-scope.js +109 -0
  89. package/dist/commands/teams-scope.js.map +1 -0
  90. package/dist/commands/teams.d.ts +64 -7
  91. package/dist/commands/teams.js +254 -60
  92. package/dist/commands/teams.js.map +1 -1
  93. package/dist/commands/upgrade.js +12 -2
  94. package/dist/commands/upgrade.js.map +1 -1
  95. package/dist/commands/use.js +2 -2
  96. package/dist/commands/use.js.map +1 -1
  97. package/dist/commands/whoami.js +1 -1
  98. package/dist/commands/whoami.js.map +1 -1
  99. package/dist/connections-api.js +1 -1
  100. package/dist/connections-api.js.map +1 -1
  101. package/dist/delegate.js +11 -4
  102. package/dist/delegate.js.map +1 -1
  103. package/dist/harness-scaffold.js +12 -0
  104. package/dist/harness-scaffold.js.map +1 -1
  105. package/dist/index.d.ts +6 -0
  106. package/dist/index.js +724 -152
  107. package/dist/index.js.map +1 -1
  108. package/dist/knowledge-api.d.ts +175 -0
  109. package/dist/knowledge-api.js +169 -0
  110. package/dist/knowledge-api.js.map +1 -0
  111. package/dist/open-url.d.ts +16 -0
  112. package/dist/open-url.js +73 -0
  113. package/dist/open-url.js.map +1 -0
  114. package/dist/parse-argv.d.ts +2 -0
  115. package/dist/parse-argv.js.map +1 -1
  116. package/dist/publish-api.d.ts +2 -1
  117. package/dist/publish-api.js +4 -3
  118. package/dist/publish-api.js.map +1 -1
  119. package/dist/pull-write.d.ts +27 -0
  120. package/dist/pull-write.js +60 -0
  121. package/dist/pull-write.js.map +1 -0
  122. package/dist/routes-api.d.ts +3 -0
  123. package/dist/routes-api.js +9 -4
  124. package/dist/routes-api.js.map +1 -1
  125. package/dist/runs-api.d.ts +7 -1
  126. package/dist/runs-api.js +21 -6
  127. package/dist/runs-api.js.map +1 -1
  128. package/dist/safe-fs.d.ts +2 -0
  129. package/dist/safe-fs.js +12 -6
  130. package/dist/safe-fs.js.map +1 -1
  131. package/dist/secret-file.d.ts +17 -0
  132. package/dist/secret-file.js +69 -0
  133. package/dist/secret-file.js.map +1 -0
  134. package/dist/skills-api.d.ts +10 -2
  135. package/dist/skills-api.js +37 -2
  136. package/dist/skills-api.js.map +1 -1
  137. package/dist/source-products-api.d.ts +63 -0
  138. package/dist/source-products-api.js +123 -0
  139. package/dist/source-products-api.js.map +1 -0
  140. package/dist/source-target.js +2 -1
  141. package/dist/source-target.js.map +1 -1
  142. package/dist/sources-api.d.ts +2 -1
  143. package/dist/sources-api.js +3 -2
  144. package/dist/sources-api.js.map +1 -1
  145. package/dist/team-connect-api.d.ts +286 -0
  146. package/dist/team-connect-api.js +107 -0
  147. package/dist/team-connect-api.js.map +1 -0
  148. package/dist/teams-api.d.ts +42 -1
  149. package/dist/teams-api.js +98 -20
  150. package/dist/teams-api.js.map +1 -1
  151. package/dist/toolchain-api.d.ts +9 -0
  152. package/dist/toolchain-api.js +17 -2
  153. package/dist/toolchain-api.js.map +1 -1
  154. package/dist/toolchain-resolve.d.ts +3 -0
  155. package/dist/toolchain-resolve.js +15 -1
  156. package/dist/toolchain-resolve.js.map +1 -1
  157. package/dist/toolchain.d.ts +6 -0
  158. package/dist/toolchain.js +19 -0
  159. package/dist/toolchain.js.map +1 -1
  160. package/dist/update-notice.js +2 -1
  161. package/dist/update-notice.js.map +1 -1
  162. package/package.json +2 -2
  163. package/templates/AGENTS.md.tmpl +6 -1
  164. package/templates/claude-skill.md.tmpl +5 -0
  165. package/templates/package.json.tmpl +4 -4
  166. package/templates/skills/build-agent/SKILL.md +115 -16
  167. package/templates/skills/build-agent/references/agent-json.md +26 -8
  168. package/templates/skills/build-agent/references/app-setup.md +2 -1
  169. package/templates/skills/build-agent/references/rollout.md +27 -4
  170. package/templates/skills/build-agent/references/set-up-an-integration.md +74 -15
  171. package/templates/skills/build-agent/references/skills.md +20 -1
  172. package/templates/skills/build-agent/references/triggers.md +84 -20
  173. package/templates/skills/build-integration/references/widget-design.md +3 -3
  174. package/templates/skills/ekanos-platform/SKILL.md +70 -17
  175. package/templates/skills/polish-widgets/references/patterns.md +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-agent-readiness.js","sourceRoot":"","sources":["../../src/commands/team-agent-readiness.ts"],"names":[],"mappings":"AASA,OAAO,EAAmB,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;;;;;;;;;;;;;GAcG;AAEH,MAAM,GAAG,GAAG,iBAAiB,CAAC;AA0B9B,MAAM,UAAU,cAAc,CAC5B,KAAqB,EACrB,MAAuB;;;IAEvB,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7C,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC;QACxB,KAAK;QACL,OAAO;QACP,IAAI,cAAE,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,GAAG,mCAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,mCAAI,IAAI;KAC5C,CAAC;AACJ,CAAC;AAED,8DAA8D;AAC9D,SAAS,aAAa,CACpB,KAAqB,EACrB,EAAE,IAAI,EAAE,MAAM,EAAmB;;IAEjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,IAAI,EAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAA;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,GAAG,SAAG,KAAK,CAAC,MAAM,mCAAI,uBAAuB,CAAC;IACpD,OAAO;QACL,OAAO,EAAE,YAAY,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,aAAa;QAChI,yDAAyD;QACzD,GAAG,EAAE,GAAG,GAAG,UAAU,GAAG,yBAAyB,IAAI,IAAI,KAAK,CAAC,GAAG,aAAa,MAAM,uCAAuC,KAAK,CAAC,IAAI,WAAW;KAClJ,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAmB;IAC9C,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK;YAC3B,CAAC,CAAC,CAAC,yCAAyC,CAAC;YAC7C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,WAAW;gBAC/B,CAAC,CAAC,CAAC,yCAAyC,CAAC;gBAC7C,CAAC,CAAC,EAAE,CAAC;QACT,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,eAAe,CAAC;QACtE,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK;KACnB,CAAC;IACF,MAAM,OAAO,GAAG;QACd,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK;KACtB,CAAC;IACF,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YACpB,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC;YACrD,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACjE,CAAC;AAED,SAAS,cAAc,CACrB,KAAqB,EACrB,EAAE,IAAI,EAAE,MAAM,EAAmB;;IAEjC,MAAM,MAAM,GAAG,GAAG,GAAG,wBAAwB,IAAI,IAAI,KAAK,CAAC,GAAG,aAAa,MAAM,EAAE,CAAC;IACpF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,QAAQ,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,4DAA4D;QAC5D,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,8BAA8B,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,gCAAgC;YAC3F,GAAG,EAAE,GAAG,GAAG,mBAAmB,KAAK,CAAC,GAAG,aAAa,MAAM,EAAE;SAC7D,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,sBAAsB;YAC/B,GAAG,EAAE,GAAG,GAAG,mBAAmB,KAAK,CAAC,GAAG,aAAa,MAAM,EAAE;SAC7D,CAAC,CAAC;IACL,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,YAAY,OAAC,IAAI,CAAC,MAAM,mCAAI,eAAe,CAAC,EAAE;YACxE,GAAG,QACD,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,mCAClC,GAAG,GAAG,qBAAqB,IAAI,IAAI,IAAI,CAAC,GAAG,aAAa,MAAM,EAAE;SACnE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;QAC3B,MAAM,GAAG,SAAG,KAAK,CAAC,MAAM,mCAAI,uBAAuB,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,GAAG,GAAG,iDAAiD;YAChE,yDAAyD;YACzD,GAAG,EAAE,GAAG,GAAG,UAAU,GAAG,yBAAyB,IAAI,IAAI,KAAK,CAAC,GAAG,aAAa,MAAM,uCAAuC,KAAK,CAAC,IAAI,WAAW;SAClJ,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,wDAAwD;YACjE,GAAG,EAAE,GAAG,GAAG,uBAAuB,IAAI,IAAI,KAAK,CAAC,GAAG,8BAA8B,MAAM,iBAAiB,GAAG,qBAAqB,MAAM,GAAG;SAC1I,CAAC,CAAC;IACL,CAAC;IACD,KAAK,MAAM,OAAO,UAAI,KAAK,CAAC,QAAQ,mCAAI,EAAE,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,KAAK;YAAE,SAAS;QAC5B,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,QAAE,OAAO,CAAC,OAAO,mCAAI,GAAG,OAAO,CAAC,IAAI,YAAY;YACvD,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAGrB;IACF,aAAa,EAAE,eAAe;IAC9B,QAAQ,EAAE,2DAA2D;IACrE,kBAAkB,EAAE,wDAAwD;IAC5E,mBAAmB,EAAE,2CAA2C;IAChE,oBAAoB,EAAE,mCAAmC;CAC1D,CAAC;AAEF,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAC5B,IAAiB,EACjB,IAAY,EACZ,MAAc;IAEd,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACrC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,UAAU;YACb,OAAO,GAAG,GAAG,eAAe,IAAI,CAAC,GAAG,YAAY,IAAI,aAAa,MAAM,cAAc,GAAG,mBAAmB,IAAI,CAAC,GAAG,aAAa,MAAM,GAAG,CAAC;QAC5I,KAAK,sBAAsB;YACzB,OAAO,GAAG,GAAG,iBAAiB,IAAI,CAAC,GAAG,aAAa,MAAM,EAAE,CAAC;QAC9D,KAAK,qBAAqB;YACxB,OAAO,4CAA4C,GAAG,8BAA8B,MAAM,GAAG,CAAC;QAChG,KAAK,oBAAoB;YACvB,OAAO,mBAAmB,IAAI,CAAC,GAAG,wCAAwC,GAAG,eAAe,CAAC;QAC/F;YACE,IAAI,IAAI,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC;YAChC,mEAAmE;YACnE,6DAA6D;YAC7D,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS;gBAC5C,CAAC,CAAC,GAAG,GAAG,kBAAkB,IAAI,IAAI,IAAI,CAAC,GAAG,SAAS,IAAI,CAAC,SAAS,aAAa,MAAM,EAAE;gBACtF,CAAC,CAAC,GAAG,GAAG,kBAAkB,IAAI,IAAI,IAAI,CAAC,GAAG,aAAa,MAAM,EAAE,CAAC;IACtE,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,UAAU,CACxB,OAA2B,EAC3B,IAAY,EACZ,MAAc;IAEd,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,KAAK,cAAc;YACjB,OAAO,GAAG,GAAG,kBAAkB,IAAI,IAAI,OAAO,CAAC,OAAO,aAAa,MAAM,EAAE,CAAC;QAC9E,KAAK,cAAc;YACjB,OAAO,OAAO,CAAC,OAAO;gBACpB,CAAC,CAAC,GAAG,GAAG,eAAe,OAAO,CAAC,OAAO,YAAY,IAAI,aAAa,MAAM,cAAc,GAAG,mBAAmB,OAAO,CAAC,OAAO,aAAa,MAAM,GAAG;gBAClJ,CAAC,CAAC,GAAG,GAAG,mBAAmB,OAAO,CAAC,OAAO,aAAa,MAAM,EAAE,CAAC;QACpE;YACE,OAAO,OAAO,CAAC,YAAY;gBACzB,CAAC,CAAC,GAAG,GAAG,kBAAkB,IAAI,IAAI,OAAO,CAAC,OAAO,iBAAiB,OAAO,CAAC,YAAY,aAAa,MAAM,EAAE;gBAC3G,CAAC,CAAC,OAAO,CAAC,GAAG,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,KAAK,YAAY;oBACvD,CAAC,CAAC,GAAG,GAAG,kBAAkB,IAAI,IAAI,OAAO,CAAC,GAAG,aAAa,MAAM,EAAE;oBAClE,CAAC,CAAC,mDAAmD,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,OAA2B;IACpD,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,KAAK,cAAc;YACjB,OAAO,cAAc,CAAC;QACxB,KAAK,cAAc;YACjB,OAAO,wBAAwB,CAAC;QAClC;YACE,OAAO,GAAG,OAAO,CAAC,IAAI,YAAY,CAAC;IACvC,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,SAAyB,EACzB,KAAsE;;IAEtE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,MAAM,IAAI,GAAG,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI;QACtB,CAAC,CAAC,SAAS,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,4BAA4B;QACnF,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,SAAS,CAAC,IAAI;QACnB,CAAC,CAAC,YAAY,IAAI,EAAE;QACpB,CAAC,CAAC,cAAc,IAAI,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC;AACpE,CAAC;AAcD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAqB,EACrB,MAAuB,EACvB,SAAyB,EACzB,QAAuB,EACvB,KAAkB;;IAElB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,GAAG,KAAK,CAAC,GAAG,OAAO,MAAM,CAAC,IAAI,aAAa,MAAA,KAAK,CAAC,gBAAgB,mCAAI,GAAG,YAAY;YACpF,KAAK,QAAQ,CAAC,SAAS,CAAC,EAAE;YAC1B,WAAW,SAAS,CAAC,IAAI,EAAE;SAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG;QACX,GAAG,KAAK,CAAC,GAAG,OAAO,MAAM,CAAC,IAAI,EAAE;QAChC,KAAK,CAAC,KAAK;YACT,CAAC,CAAC,UAAU,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,yBAAyB;YACzD,CAAC,CAAC,KAAK,CAAC,IAAI;gBACV,CAAC,CAAC,YAAY,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,2BAA2B;gBACrF,CAAC,CAAC,IAAI,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,GAAG;QAC3E,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,WAAW,MAAA,KAAK,CAAC,MAAM,mCAAI,QAAQ,EAAE;QACrC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,wBAAwB;KACxE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,CAAC,EACD,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CACrD,CAAC;IACF,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS;YACxB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,OAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,mCACjD,GAAG,GAAG,qBAAqB,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACpF,MAAM,MAAM,GACV,IAAI,CAAC,aAAa,IAAI,KAAK;YACzB,CAAC,CAAC;gBACE,GAAG,MAAM,KAAK,gBAAgB,CAAC,KAAK,CAAC,EAAE;gBACvC,GAAG,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAK,kCAAO,MAAM,KAAE,OAAO,EAAE,IAAI,CAAC,GAAG,IAAG,CAAC,EAAE;aAC3E;YACH,CAAC,CAAC,EAAE,CAAC;QACT,OAAO;YACL,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,YAAY,CAAC,IAAI,CAAC,EAAE;YAC3C,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,GAAG,MAAM;SACV,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,CAAC,EACD,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CACnB,CAAC,OAAO,EAAE,EAAE,kBAAC,OAAC,OAAO,CAAC,OAAO,mCAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,GAAA,CACtD,CACF,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;;;QACzD,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,OAAC,OAAO,CAAC,OAAO,mCAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO,CAAC,KAAK,KAAK,KAAK,IAAI,QAAQ,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,OAAC,KAAK,CAAC,QAAQ,mCAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,kBACxD,SAAS,CAAC,QAAQ,CAAC,QAAQ,OAAC,OAAO,CAAC,OAAO,mCAAI,OAAO,CAAC,IAAI,CAAC,GAAA,CAC7D,CAAC;QACF,MAAM,KAAK,GAAG,OAAO;YACnB,CAAC,CAAC,OAAO,CAAC,KAAK;gBACb,CAAC,CAAC,gBAAgB,UAAU,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;gBACpH,CAAC,CAAC,KAAK,MAAA,OAAO,CAAC,OAAO,mCAAI,GAAG,OAAO,CAAC,IAAI,YAAY,EAAE;YACzD,CAAC,CAAC,KAAK,MAAA,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,mCAAI,WAAW,EAAE,CAAC;QACtD,mEAAmE;QACnE,gEAAgE;QAChE,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO;YAC/B,CAAC,CAAC,OAAC,QAAQ,CAAC,MAAM,mCAAI,EAAE,CAAC,CAAC,MAAM,CAC5B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAC7C;YACH,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;YAC7B,CAAC,CAAC,MAAA,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,0CAAE,IAAI,CAAC,CAAC,CAAC;YAC3D,CAAC,CAAC,MAAA,QAAQ,CAAC,IAAI,0CAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAChE,MAAM,KAAK,GAAG;YACZ,KAAK;YACL,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM;gBACpC,CAAC,CAAC;oBACE,SAAS;wBACP,CAAC,CAAC,cAAc,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,MAAM,EAAE;wBAC1D,CAAC,CAAC,cAAc;iBACnB;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK;gBACP,CAAC,CAAC;oBACE,OAAO;wBACL,CAAC,CAAC,YAAY,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE;wBACnD,CAAC,CAAC,YAAY;iBACjB;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,OAAO;YACL,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YAC3C,GAAG,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK;gBAC3B,CAAC,CAAC;oBACE,GAAG,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE;iBACzE;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO;QAC9B,CAAC,CAAC;YACE,KAAK,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE;YAClD,GAAG,MAAM,KAAK,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE;SACtC;QACH,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;QACL,IAAI;QACJ,GAAG,QAAQ;QACX,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1E,GAAG,MAAM;QACT,KAAK,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;QACjC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,aAAa,GAA2B;IAC5C,MAAM,EAAE,iBAAiB;IACzB,QAAQ,EAAE,sBAAsB;IAChC,OAAO,EAAE,8BAA8B;CACxC,CAAC;AAEF,SAAS,YAAY,CAAC,IAAiB;;IACrC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,SAAS;YACnB,CAAC,CAAC,wBAAwB;YAC1B,CAAC,CAAC,4BAA4B,CAAC;IACnC,CAAC;IACD,MAAM,GAAG,GACP,IAAI,CAAC,GAAG,KAAK,QAAQ;QACnB,CAAC,CAAC,uBAAuB;QACzB,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,QAAQ;YACrB,CAAC,CAAC,OAAO,MAAA,IAAI,CAAC,SAAS,mCAAI,oBAAoB,wBAAwB;YACvE,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,MAAM;gBACnB,CAAC,CAAC,qBAAqB;gBACvB,CAAC,CAAC,IAAI,CAAC;IACf,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,MAAM,GACV,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS;YACrC,CAAC,CAAC,cAAc,IAAI,CAAC,SAAS,EAAE;YAChC,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,QAAQ,GACZ,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,eAAe;YAC5C,CAAC,CAAC,KAAK,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;YACnC,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,KAAK,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE,CAAC;IACvD,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,OAAC,IAAI,CAAC,MAAM,mCAAI,eAAe,CAAC,CAAC;IAC5D,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;AACrF,CAAC","sourcesContent":["import type {\n AgentRunSummary,\n ChannelRequirement,\n Requirement,\n TeamAgentEntry,\n TeamAgentHold,\n TeamIntegrationEvent,\n} from '@ekanos/integration-schema';\n\nimport { type ScopeFacts, scopeFix, scopeHiddenWords } from './scope-notice';\n\n/**\n * \"Is this agent live on this team, and if not, why?\" — one answer for\n * `teams agents show` and the summary line of `teams agents list`, built only\n * from what the host already reports (CLI audit 2026-10-19, §3).\n *\n * Live is: on, on a published version, every connection it needs made,\n * access confirmed by the person it runs as, at least one trigger on, and\n * every trigger's events able to reach it. Each gap is a step with one fix,\n * in the order they have to be done; the first step's fix is \"Next\".\n *\n * An agent HELD on an earlier version (a newer one reaches further than the\n * person it runs as confirmed) is still live — it runs the version it is on\n * — so the hold is not a step: it is `pending`, said beside \"Live\", and its\n * confirm command is \"Next\" once nothing else is.\n */\n\nconst CLI = 'npx @ekanos/cli';\n\nexport interface ReadinessStep {\n /** What is missing, in words. */\n problem: string;\n /** The one command (or app step) that fixes it. */\n fix: string;\n}\n\nexport interface AgentReadiness {\n live: boolean;\n steps: ReadinessStep[];\n /**\n * An update waiting for the runs-as person's confirmation; the agent runs\n * its current version meanwhile. Null when none.\n */\n pending: ReadinessStep | null;\n /** The first step's fix, else the pending update's; null when neither. */\n next: string | null;\n}\n\nexport interface ReadinessTarget {\n team: string;\n source: string;\n}\n\nexport function agentReadiness(\n entry: TeamAgentEntry,\n target: ReadinessTarget,\n): AgentReadiness {\n const steps = readinessSteps(entry, target);\n const pending = pendingUpdate(entry, target);\n return {\n live: steps.length === 0,\n steps,\n pending,\n next: steps[0]?.fix ?? pending?.fix ?? null,\n };\n}\n\n/** The update a held agent waits for, and who confirms it. */\nfunction pendingUpdate(\n entry: TeamAgentEntry,\n { team, source }: ReadinessTarget,\n): ReadinessStep | null {\n const agent = entry.agent;\n if (!agent?.held) return null;\n const who = agent.runsAs ?? 'the person it runs as';\n return {\n problem: `held on v${agent.version ?? '?'}: v${agent.held.waiting} ${describeHold(agent.held)}, and waits for ${who} to confirm`,\n // Only that person can confirm, signed in as themselves.\n fix: `${who} runs: ${CLI} teams agents confirm ${team} ${entry.key} --source ${source} (or confirms in the app: Agents › ${entry.name} › Setup)`,\n };\n}\n\n/**\n * What a waiting version adds over the one running, in words:\n * \"adds zendesk_update_ticket; lets zendesk_add_tag run without approval\".\n */\nexport function describeHold(hold: TeamAgentHold): string {\n const adds = [\n ...(hold.adds.scope === 'all'\n ? ['every tool of the products it can reach']\n : hold.adds.scope === 'read_only'\n ? ['every read of the products it can reach']\n : []),\n ...hold.adds.products.map((product) => `${product.name} (every tool)`),\n ...hold.adds.tools,\n ];\n const loosens = [\n ...(hold.loosens.writes ? ['writes'] : []),\n ...(hold.loosens.reads ? ['reads'] : []),\n ...hold.loosens.tools,\n ];\n const parts = [\n ...(adds.length > 0 ? [`adds ${adds.join(', ')}`] : []),\n ...(loosens.length > 0\n ? [`lets ${loosens.join(', ')} run without approval`]\n : []),\n ];\n return parts.length > 0 ? parts.join('; ') : 'reaches further';\n}\n\nfunction readinessSteps(\n entry: TeamAgentEntry,\n { team, source }: ReadinessTarget,\n): ReadinessStep[] {\n const enable = `${CLI} teams agents enable ${team} ${entry.key} --source ${source}`;\n const agent = entry.agent;\n if (!agent) return [{ problem: `off for ${team}`, fix: enable }];\n if (agent.status !== 'active') {\n return [{ problem: `${agent.status} for ${team}`, fix: enable }];\n }\n\n const steps: ReadinessStep[] = [];\n if (agent.draft) {\n // A team testing a draft runs it only when started by hand.\n steps.push({\n problem: `testing unpublished draft v${agent.version ?? '?'}: its triggers do not start it`,\n fix: `${CLI} agents publish ${entry.key} --source ${source}`,\n });\n } else if (agent.version === null) {\n steps.push({\n problem: 'no published version',\n fix: `${CLI} agents publish ${entry.key} --source ${source}`,\n });\n }\n for (const item of agent.missing) {\n steps.push({\n problem: `${item.name}: ${REASON_WORDS[item.reason ?? 'not_connected']}`,\n fix:\n requirementFix(item, team, source) ??\n `${CLI} teams mcp status ${team} ${item.key} --source ${source}`,\n });\n }\n if (!agent.accessConfirmed) {\n const who = agent.runsAs ?? 'the person it runs as';\n steps.push({\n problem: `${who} has not confirmed it may use their connections`,\n // Only that person can confirm, signed in as themselves.\n fix: `${who} runs: ${CLI} teams agents confirm ${team} ${entry.key} --source ${source} (or confirms in the app: Agents › ${entry.name} › Setup)`,\n });\n }\n if (!agent.triggers.some((trigger) => trigger.enabled)) {\n steps.push({\n problem: 'no trigger is on, so it only runs when started by hand',\n fix: `${CLI} teams triggers add ${team} ${entry.key} event <event-id> --source ${source} (event ids: ${CLI} catalog --source ${source})`,\n });\n }\n for (const channel of agent.channels ?? []) {\n if (channel.ready) continue;\n steps.push({\n problem: channel.problem ?? `${channel.name} not ready`,\n fix: channelFix(channel, team, source),\n });\n }\n return steps;\n}\n\nexport const REASON_WORDS: Record<\n NonNullable<Requirement['reason']>,\n string\n> = {\n not_connected: 'not connected',\n no_route: 'no route maps the Source connection’s events to this team',\n source_unsupported: 'the integration no longer supports a Source connection',\n source_not_entitled: 'the product is not enabled for the Source',\n source_not_connected: 'the Source connection is not made',\n};\n\n/** The one command that makes a requirement, or null when none can. */\nexport function requirementFix(\n item: Requirement,\n team: string,\n source: string,\n): string | null {\n if (item.kind === 'mcp') return null;\n switch (item.reason) {\n case 'no_route':\n return `${CLI} routes set ${item.key} <value> ${team} --source ${source} (values: ${CLI} routes options ${item.key} --source ${source})`;\n case 'source_not_connected':\n return `${CLI} apps connect ${item.key} --source ${source}`;\n case 'source_not_entitled':\n return `a super-admin enables it for the Source (${CLI} sources products --source ${source})`;\n case 'source_unsupported':\n return `set connections.${item.key}.owner to \"team\" in agent.json, then ${CLI} agents apply`;\n default:\n if (item.connected) return null;\n // A per-person product is the runs-as person's connection, not the\n // caller's: connecting your own leaves the agent missing it.\n return item.via === 'person' && item.viaDetail\n ? `${CLI} teams connect ${team} ${item.key} --as ${item.viaDetail} --source ${source}`\n : `${CLI} teams connect ${team} ${item.key} --source ${source}`;\n }\n}\n\n/** The one command that makes a channel ready, or the app step. */\nexport function channelFix(\n channel: ChannelRequirement,\n team: string,\n source: string,\n): string {\n switch (channel.arrival) {\n case 'team-webhook':\n return `${CLI} teams webhook ${team} ${channel.product} --source ${source}`;\n case 'source-route':\n return channel.webhook\n ? `${CLI} routes set ${channel.product} <value> ${team} --source ${source} (values: ${CLI} routes options ${channel.product} --source ${source})`\n : `${CLI} routes webhook ${channel.product} --source ${source}`;\n default:\n return channel.connectionId\n ? `${CLI} teams connect ${team} ${channel.product} --connection ${channel.connectionId} --source ${source}`\n : channel.key === 'slack' || channel.key === 'linear-app'\n ? `${CLI} teams connect ${team} ${channel.key} --source ${source}`\n : `install it on the agent's Triggers tab in the app`;\n }\n}\n\n/** How the events of a ready channel reach the agent. */\nexport function reachedVia(channel: ChannelRequirement): string {\n switch (channel.arrival) {\n case 'team-webhook':\n return 'team webhook';\n case 'source-route':\n return 'Source webhook, routed';\n default:\n return `${channel.name} installed`;\n }\n}\n\n/** A fix as a line: a command is run in the terminal, an app step is not. */\nexport function fixLine(fix: string): string {\n return fix.startsWith(CLI) ? `in your terminal: ${fix}` : fix;\n}\n\n/**\n * \"Live: yes\" or \"Live: no — N steps left\", and an update waiting for\n * confirmation: \"Live: yes (on v4; v5 waiting for confirmation)\".\n */\nexport function liveLine(\n readiness: AgentReadiness,\n agent?: { version: number | null; held?: TeamAgentHold | null } | null,\n): string {\n const left = readiness.steps.length;\n const held = agent?.held\n ? ` (on v${agent.version ?? '?'}; v${agent.held.waiting} waiting for confirmation)`\n : '';\n return readiness.live\n ? `Live: yes${held}`\n : `Live: no — ${left} step${left === 1 ? '' : 's'} left${held}`;\n}\n\n/* ---------------------------------------------------------------------- */\n/* teams agents show */\n/* ---------------------------------------------------------------------- */\n\n/** What happened lately, read alongside the agent; each part optional. */\nexport interface AgentActivity {\n /** The agent's recent runs, newest first. */\n runs: AgentRunSummary[] | null;\n /** The team's recent integration events, newest first. */\n events: TeamIntegrationEvent[] | null;\n}\n\n/**\n * One line per product, per trigger, then Live and Next. A product the\n * team's product scopes hide from it in the app says so — connected or not,\n * the team cannot see it there (`scope`, the team's scopes).\n */\nexport function describeAgentReadiness(\n entry: TeamAgentEntry,\n target: ReadinessTarget,\n readiness: AgentReadiness,\n activity: AgentActivity,\n scope?: ScopeFacts,\n): string {\n const agent = entry.agent;\n if (!agent) {\n return [\n `${entry.key} on ${target.team} · off · v${entry.publishedVersion ?? '?'} published`,\n ` ${liveLine(readiness)}`,\n ` Next: ${readiness.next}`,\n ].join('\\n');\n }\n\n const head = [\n `${entry.key} on ${target.team}`,\n agent.draft\n ? `draft v${agent.version ?? '?'} (testing, unpublished)`\n : agent.held\n ? `held on v${agent.version ?? '?'}, v${agent.held.waiting} waiting for confirmation`\n : `v${agent.version ?? '?'} (${agent.pinned ? 'pinned' : 'following'})`,\n ...(agent.status === 'active' ? [] : [agent.status]),\n `runs as ${agent.runsAs ?? 'nobody'}`,\n agent.accessConfirmed ? '✓ access confirmed' : '✗ access not confirmed',\n ].join(' · ');\n\n const width = Math.max(\n 8,\n ...agent.requirements.map((item) => item.key.length),\n );\n const pad = (label: string) => label.padEnd(width);\n const indent = ' '.repeat(width + 4);\n\n const products = agent.requirements.flatMap((item) => {\n const fix = item.connected\n ? null\n : (requirementFix(item, target.team, target.source) ??\n `${CLI} teams mcp status ${target.team} ${item.key} --source ${target.source}`);\n const hidden =\n item.hiddenByScope && scope\n ? [\n `${indent}! ${scopeHiddenWords(scope)}`,\n `${indent}→ ${fixLine(scopeFix(scope, { ...target, product: item.key }))}`,\n ]\n : [];\n return [\n ` ${pad(item.key)} ${productState(item)}`,\n ...(fix ? [`${indent}→ ${fixLine(fix)}`] : []),\n ...hidden,\n ];\n });\n\n const nameWidth = Math.max(\n 0,\n ...agent.triggers.map(\n (trigger) => (trigger.eventId ?? trigger.type).length,\n ),\n );\n const triggers = agent.triggers.flatMap((trigger, index) => {\n const label = index === 0 ? pad('triggers') : pad('');\n const name = (trigger.eventId ?? trigger.type).padEnd(nameWidth);\n if (!trigger.enabled) return [` ${label} ${name} (off)`];\n const channel = (agent.channels ?? []).find((candidate) =>\n candidate.triggers.includes(trigger.eventId ?? trigger.type),\n );\n const reach = channel\n ? channel.ready\n ? `✓ reachable (${reachedVia(channel)}${channel.lastDeliveryAt ? `, last delivery ${channel.lastDeliveryAt}` : ''})`\n : `✗ ${channel.problem ?? `${channel.name} not ready`}`\n : `✓ ${TRIGGER_REACH[trigger.type] ?? 'reachable'}`;\n // An event trigger's runs are the ones its own events started; any\n // other trigger's, the agent's latest run of that trigger type.\n const ownEvents = trigger.eventId\n ? (activity.events ?? []).filter(\n (event) => event.eventId === trigger.eventId,\n )\n : [];\n const lastEvent = ownEvents[0];\n const lastRun = trigger.eventId\n ? ownEvents.find((event) => event.runs.length > 0)?.runs[0]\n : activity.runs?.find((run) => run.trigger === trigger.type);\n const known = trigger.eventId ? activity.events : activity.runs;\n const facts = [\n reach,\n ...(trigger.eventId && activity.events\n ? [\n lastEvent\n ? `last event ${lastEvent.receivedAt} ${lastEvent.status}`\n : 'no event yet',\n ]\n : []),\n ...(known\n ? [\n lastRun\n ? `last run ${lastRun.startedAt} ${lastRun.status}`\n : 'no run yet',\n ]\n : []),\n ];\n return [\n ` ${label} ${name} ${facts.join(' · ')}`,\n ...(channel && !channel.ready\n ? [\n `${indent}→ ${fixLine(channelFix(channel, target.team, target.source))}`,\n ]\n : []),\n ];\n });\n\n const update = readiness.pending\n ? [\n ` ${pad('update')} ${readiness.pending.problem}`,\n `${indent}→ ${readiness.pending.fix}`,\n ]\n : [];\n\n return [\n head,\n ...products,\n ...(agent.triggers.length > 0 ? triggers : [` ${pad('triggers')} none`]),\n ...update,\n ` ${liveLine(readiness, agent)}`,\n ...(readiness.next ? [` Next: ${readiness.next}`] : []),\n ].join('\\n');\n}\n\nconst TRIGGER_REACH: Record<string, string> = {\n manual: 'started by hand',\n schedule: 'runs on its schedule',\n webhook: 'reachable at its trigger URL',\n};\n\nfunction productState(item: Requirement): string {\n if (item.kind === 'mcp') {\n return item.connected\n ? '✓ MCP server connected'\n : '✗ MCP server not signed in';\n }\n const via =\n item.via === 'source'\n ? 'via Source connection'\n : item.via === 'person'\n ? `via ${item.viaDetail ?? 'the runs-as person'}'s personal connection`\n : item.via === 'team'\n ? 'via team connection'\n : null;\n if (item.connected) {\n const routes =\n item.via === 'source' && item.viaDetail\n ? ` · routes: ${item.viaDetail}`\n : '';\n const fallback =\n item.reason && item.reason !== 'not_connected'\n ? ` (${REASON_WORDS[item.reason]})`\n : '';\n return `✓ ${via ?? 'connected'}${routes}${fallback}`;\n }\n const reason = REASON_WORDS[item.reason ?? 'not_connected'];\n return `✗ ${via ? `${via} — ` : ''}${reason}${item.required ? '' : ' (optional)'}`;\n}\n"]}
@@ -1,9 +1,30 @@
1
+ import { type ChannelRequirement, type Requirement, type TeamAgentAccess } from '@ekanos/integration-schema';
1
2
  import type { CliContext } from '../context.js';
2
3
  import type { ExitCode } from '../exit-codes.js';
3
4
  import { type TeamAgentRun } from './team-agents.js';
4
5
  /**
5
- * `ekanos teams agents list|enable|disable|pin|unpin|policy` — a team's
6
- * provided agents, turned on, versioned and given an approval policy by the
7
- * Source admin.
6
+ * `ekanos teams agents list|show|enable|confirm|disable|pin|unpin|policy|skills` —
7
+ * a team's provided agents, turned on, versioned, given an approval policy
8
+ * and skills by the Source admin. `enable|pin … --draft` puts one team on
9
+ * the template's latest, unpublished version to test it there before
10
+ * publishing. `confirm` (and `--confirm-access`) is the one thing only the
11
+ * person the agent runs as can do: consent, as themselves, that it may use
12
+ * their connections in runs no one watches.
13
+ * `show` answers "is this agent live, and if not, why?" for one agent; `list`
14
+ * ends each agent with the same verdict.
8
15
  */
9
16
  export declare function runTeamAgentsArea(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;
17
+ /**
18
+ * What the agent still needs connected, each with why and the command that
19
+ * makes it; then any product working on another connection than the one its
20
+ * template names (the Source connection unusable, the team's own used).
21
+ */
22
+ export declare function requirementLines(requirements: Requirement[], missing: Requirement[], team: string, source: string): string[];
23
+ /**
24
+ * What the agent's triggers need installed before they can fire: missing
25
+ * ones first, each with the command that installs it. A trigger listed above
26
+ * with its channel missing here is one that will never start a run.
27
+ */
28
+ export declare function channelLines(channels: ChannelRequirement[], team: string, source: string): string[];
29
+ /** What a confirmation covers, in words: whose connections, to what. */
30
+ export declare function describeAccess(access: TeamAgentAccess): string;
@@ -1,14 +1,22 @@
1
- import { TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, } from '@ekanos/integration-schema';
2
- import { usageError } from '../errors.js';
3
- import { call } from '../teams-api.js';
1
+ import { AgentRunListSchema, TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, TeamAgentSkillsSchema, } from '@ekanos/integration-schema';
2
+ import { invalidStateError, notFoundError, usageError } from '../errors.js';
3
+ import { call, listTeamEvents } from '../teams-api.js';
4
+ import { REASON_WORDS, agentReadiness, channelFix, describeAgentReadiness, describeHold, fixLine, liveLine, reachedVia, requirementFix, } from './team-agent-readiness.js';
4
5
  import { requireOperand, usageFor } from './team-agents.js';
5
6
  /**
6
- * `ekanos teams agents list|enable|disable|pin|unpin|policy` — a team's
7
- * provided agents, turned on, versioned and given an approval policy by the
8
- * Source admin.
7
+ * `ekanos teams agents list|show|enable|confirm|disable|pin|unpin|policy|skills` —
8
+ * a team's provided agents, turned on, versioned, given an approval policy
9
+ * and skills by the Source admin. `enable|pin … --draft` puts one team on
10
+ * the template's latest, unpublished version to test it there before
11
+ * publishing. `confirm` (and `--confirm-access`) is the one thing only the
12
+ * person the agent runs as can do: consent, as themselves, that it may use
13
+ * their connections in runs no one watches.
14
+ * `show` answers "is this agent live, and if not, why?" for one agent; `list`
15
+ * ends each agent with the same verdict.
9
16
  */
10
17
  export async function runTeamAgentsArea(ctx, run) {
11
- var _a;
18
+ var _a, _b, _c;
19
+ var _d, _e, _f;
12
20
  const team = requireOperand(run.operands[0], 'team slug', 'agents');
13
21
  const base = `/api/partner/teams/${encodeURIComponent(team)}/agents`;
14
22
  if (run.verb === 'list') {
@@ -18,14 +26,15 @@ export async function runTeamAgentsArea(ctx, run) {
18
26
  path: base,
19
27
  source: run.source,
20
28
  }));
21
- return ctx.succeed(Object.assign({ host: run.host }, list), [
29
+ const target = { team: list.team.slug, source: run.source };
30
+ return ctx.succeed(Object.assign(Object.assign({ host: run.host }, list), { agents: list.agents.map((entry) => (Object.assign(Object.assign({}, entry), { readiness: agentReadiness(entry, target) }))) }), [
22
31
  ctx.ui.result({
23
32
  title: list.agents.length === 0
24
33
  ? `No agents are provided for ${list.team.slug}`
25
34
  : `Agents for ${list.team.slug}`,
26
35
  tone: list.agents.length === 0 ? 'warn' : 'ok',
27
36
  }),
28
- ...list.agents.map(describeEntry),
37
+ ...list.agents.map((entry) => describeEntry(entry, list.team.slug, run.source)),
29
38
  list.mcpServers.length > 0
30
39
  ? `\nMCP servers: ${list.mcpServers.map((server) => `${server.key} (${server.status})`).join(', ')}`
31
40
  : '',
@@ -36,40 +45,130 @@ export async function runTeamAgentsArea(ctx, run) {
36
45
  const key = requireOperand(run.operands[1], 'agent key', 'agents');
37
46
  const path = `${base}/${encodeURIComponent(key)}`;
38
47
  switch (run.verb) {
48
+ case 'show':
49
+ expectOperands(run, 2);
50
+ return show(ctx, run, base, key);
39
51
  case 'enable': {
40
52
  expectOperands(run, 2);
41
53
  const as = stringFlag(run, 'as');
42
- const result = await change(run, `${path}/enable`, 'POST', Object.assign({}, (as ? { as } : {})));
43
- return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned on ${result.slug} for ${result.team.slug}`));
54
+ const draft = ((_a = run.args.flags) === null || _a === void 0 ? void 0 : _a.draft) === true;
55
+ const confirmAccess = ((_b = run.args.flags) === null || _b === void 0 ? void 0 : _b['confirm-access']) === true;
56
+ const result = await change(run, `${path}/enable`, 'POST', Object.assign(Object.assign(Object.assign({}, (as ? { as } : {})), (draft ? { draft: true } : {})), (confirmAccess ? { confirmAccess: true } : {})));
57
+ if (draft)
58
+ requireDraftHost(result, 'enabled');
59
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${draft
60
+ ? `Testing draft v${(_d = result.version) !== null && _d !== void 0 ? _d : '?'} of ${result.slug} on ${result.team.slug}`
61
+ : `Turned on ${result.slug} for ${result.team.slug}`}${confirmAccess && result.accessConfirmed ? ', and you confirmed it may use your connections' : ''}`, run.source, { confirmRequested: confirmAccess }));
62
+ }
63
+ case 'confirm': {
64
+ expectOperands(run, 2);
65
+ // Confirm what the person is shown, never a publish that lands after:
66
+ // the host refuses if the version moved (AGENT_VERSION_CHANGED).
67
+ const shown = await shownVersion(ctx, run, base, key);
68
+ const result = await change(run, `${path}/confirm`, 'POST', shown === null ? {} : { expectedVersion: shown });
69
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, result.advanced
70
+ ? `You confirmed the update: ${result.slug} on ${result.team.slug} moved from v${result.advanced.from} to v${result.advanced.to}`
71
+ : `You confirmed ${result.slug} on ${result.team.slug} may use your connections`, run.source, { confirmRequested: true }));
44
72
  }
45
73
  case 'disable': {
46
74
  expectOperands(run, 2);
75
+ if (!run.args.yes) {
76
+ throw invalidStateError(`Turning ${key} off for ${team} pauses it: nothing starts it for that team until it is turned on again, and turning it on is refused once the person it runs as has left the team.`, `Re-run with --yes: ekanos teams agents disable ${team} ${key} --yes`);
77
+ }
47
78
  const result = await change(run, `${path}/disable`, 'POST', {});
48
- return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned off ${result.slug} for ${result.team.slug}`));
79
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned off ${result.slug} for ${result.team.slug}`, run.source));
49
80
  }
50
81
  case 'pin': {
82
+ if (((_c = run.args.flags) === null || _c === void 0 ? void 0 : _c.draft) === true) {
83
+ expectOperands(run, 2);
84
+ const result = await change(run, `${path}/pin`, 'PUT', {
85
+ version: null,
86
+ draft: true,
87
+ });
88
+ requireDraftHost(result, 'pinned');
89
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Testing draft v${(_e = result.version) !== null && _e !== void 0 ? _e : '?'} of ${result.slug} on ${result.team.slug}`, run.source));
90
+ }
51
91
  expectOperands(run, 3);
52
92
  const version = Number(run.operands[2]);
53
93
  if (!Number.isInteger(version) || version < 1) {
54
94
  throw usageError(run.operands[2]
55
95
  ? `"${run.operands[2]}" is not a version number.`
56
- : 'Name the version to pin.', `e.g. "ekanos teams agents pin ${team} ${key} 3". "ekanos agents show ${key}" lists its versions.`);
96
+ : 'Name the version to pin.', `e.g. "ekanos teams agents pin ${team} ${key} 3", or "--draft" to test the unpublished draft. "ekanos agents show ${key}" lists its versions.`);
57
97
  }
58
98
  const result = await change(run, `${path}/pin`, 'PUT', { version });
59
- return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} stays on v${(_a = result.version) !== null && _a !== void 0 ? _a : version} of ${result.slug}`));
99
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} stays on v${(_f = result.version) !== null && _f !== void 0 ? _f : version} of ${result.slug}`, run.source));
60
100
  }
61
101
  case 'unpin': {
62
102
  expectOperands(run, 2);
63
103
  const result = await change(run, `${path}/pin`, 'PUT', { version: null });
64
- return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}`));
104
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}`, run.source));
65
105
  }
66
106
  case 'policy':
67
107
  return policy(ctx, run, team, key, `${path}/policy`);
108
+ case 'skills':
109
+ return skills(ctx, run, team, key, `${path}/skills`);
68
110
  default:
69
111
  throw usageError(`Unknown teams agents subcommand "${run.verb}".`, usageFor('agents'));
70
112
  }
71
113
  }
114
+ /**
115
+ * One agent on one team: each product and whose connection it acts through,
116
+ * each trigger and how its events reach the agent (with the last event and
117
+ * the last run), access, "Live: yes/no" and exactly one Next. Reads the
118
+ * team's agents, then its recent runs and events; a host without the
119
+ * activity reads still answers the rest.
120
+ */
121
+ async function show(ctx, run, base, key) {
122
+ var _a, _b, _c;
123
+ const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
124
+ method: 'GET',
125
+ path: base,
126
+ source: run.source,
127
+ }));
128
+ const entry = list.agents.find((candidate) => candidate.key === key);
129
+ if (!entry) {
130
+ throw notFoundError(`No agent "${key}" is provided for ${list.team.slug}.`, `"ekanos teams agents list ${list.team.slug}" lists the agents provided for it.`);
131
+ }
132
+ const target = { team: list.team.slug, source: run.source };
133
+ const readiness = agentReadiness(entry, target);
134
+ const [runs, events] = entry.agent
135
+ ? await Promise.all([
136
+ activity(ctx, 'runs', () => run.client.call((token) => call(run.host, token, AgentRunListSchema, {
137
+ method: 'GET',
138
+ path: `/api/partner/teams/${encodeURIComponent(target.team)}/runs?agent=${encodeURIComponent(key)}`,
139
+ source: run.source,
140
+ }))),
141
+ entry.agent.triggers.some((trigger) => trigger.eventId)
142
+ ? activity(ctx, 'events', () => run.client.call((token) => listTeamEvents(run.host, token, { source: run.source, team: target.team }, { limit: 100 })))
143
+ : Promise.resolve(null),
144
+ ])
145
+ : [null, null];
146
+ return ctx.succeed({
147
+ host: run.host,
148
+ team: list.team,
149
+ agent: entry,
150
+ readiness,
151
+ lastRun: (_a = runs === null || runs === void 0 ? void 0 : runs.runs[0]) !== null && _a !== void 0 ? _a : null,
152
+ recentEvents: events
153
+ ? events.events.filter((event) => { var _a; return (_a = entry.agent) === null || _a === void 0 ? void 0 : _a.triggers.some((trigger) => trigger.eventId === event.eventId); })
154
+ : null,
155
+ }, describeAgentReadiness(entry, target, readiness, {
156
+ runs: (_b = runs === null || runs === void 0 ? void 0 : runs.runs) !== null && _b !== void 0 ? _b : null,
157
+ events: (_c = events === null || events === void 0 ? void 0 : events.events) !== null && _c !== void 0 ? _c : null,
158
+ }, list.scope));
159
+ }
160
+ /** A read `show` can do without: on failure, say so and carry on. */
161
+ async function activity(ctx, what, read) {
162
+ try {
163
+ return await read();
164
+ }
165
+ catch (error) {
166
+ ctx.log(`Could not read the team's recent ${what}: ${error instanceof Error ? error.message : String(error)}`);
167
+ return null;
168
+ }
169
+ }
72
170
  async function policy(ctx, run, team, key, path) {
171
+ var _a;
73
172
  const [action, tool, decision] = run.operands.slice(2);
74
173
  const change = {};
75
174
  const reads = approvalFlag(run, 'reads');
@@ -95,21 +194,87 @@ async function policy(ctx, run, team, key, path) {
95
194
  throw usageError(`Unknown policy action "${action}".`, usageFor('agents'));
96
195
  }
97
196
  const writing = Object.keys(change).length > 0;
98
- const result = await run.client.call((token) => call(run.host, token, TeamAgentPolicySchema, Object.assign({ method: writing ? 'PUT' : 'GET', path, source: run.source }, (writing ? { body: change } : {}))));
99
- return ctx.succeed(Object.assign({ host: run.host }, result), describePolicy(ctx, result, writing));
197
+ const confirmAccess = ((_a = run.args.flags) === null || _a === void 0 ? void 0 : _a['confirm-access']) === true;
198
+ if (confirmAccess && !writing) {
199
+ throw usageError('--confirm-access goes with a policy change.', `To confirm on its own: "ekanos teams agents confirm ${team} ${key}".`);
200
+ }
201
+ const result = await run.client.call((token) => call(run.host, token, TeamAgentPolicySchema, Object.assign({ method: writing ? 'PUT' : 'GET', path, source: run.source }, (writing
202
+ ? { body: Object.assign(Object.assign({}, change), (confirmAccess ? { confirmAccess } : {})) }
203
+ : {}))));
204
+ return ctx.succeed(Object.assign({ host: run.host }, result), describePolicy(ctx, result, writing, run.source));
205
+ }
206
+ /**
207
+ * `teams agents skills <team> <key> [add|remove <skill>]` — the skills the
208
+ * team's agent reads. A provided agent takes the team's own only where its
209
+ * template allows (`teamCustomization.skills`); its template's stay.
210
+ */
211
+ async function skills(ctx, run, team, key, path) {
212
+ const [action, slug, extra] = run.operands.slice(2);
213
+ if (extra !== undefined) {
214
+ throw usageError(`Unexpected argument "${extra}".`, usageFor('agents'));
215
+ }
216
+ let change = null;
217
+ if (action === 'add' || action === 'remove') {
218
+ if (!slug) {
219
+ throw usageError(`skills ${action} needs a skill slug.`, `e.g. "ekanos teams agents skills ${team} ${key} ${action} refund-policy". "ekanos skills list --team ${team}" lists the team's skills.`);
220
+ }
221
+ change = { [action]: [slug.trim().toLowerCase()] };
222
+ }
223
+ else if (action !== undefined) {
224
+ throw usageError(`Unknown skills action "${action}".`, usageFor('agents'));
225
+ }
226
+ const result = await run.client.call((token) => call(run.host, token, TeamAgentSkillsSchema, Object.assign({ method: change ? 'PUT' : 'GET', path, source: run.source }, (change ? { body: change } : {}))));
227
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeSkills(ctx, result, change));
228
+ }
229
+ function describeSkills(ctx, result, change) {
230
+ const [verb, slug] = (change === null || change === void 0 ? void 0 : change.add)
231
+ ? ['Attached', change.add[0]]
232
+ : (change === null || change === void 0 ? void 0 : change.remove)
233
+ ? ['Detached', change.remove[0]]
234
+ : [null, null];
235
+ const head = ctx.ui.result({
236
+ title: verb
237
+ ? `${verb} ${slug} ${verb === 'Attached' ? 'to' : 'from'} ${result.slug} on ${result.team.slug}`
238
+ : `Skills of ${result.slug} on ${result.team.slug}`,
239
+ tone: result.editable ? 'ok' : 'warn',
240
+ rows: [
241
+ [
242
+ 'team skills',
243
+ result.editable ? 'allowed' : 'no — follows the template',
244
+ ],
245
+ ],
246
+ notes: result.lockedReason ? [result.lockedReason] : [],
247
+ });
248
+ if (result.skills.length === 0)
249
+ return `${head}\n\nNo skills attached.`;
250
+ return `${head}\n\n${ctx.ui.table(['skill', 'name', 'from'], result.skills.map((skill) => [
251
+ skill.slug,
252
+ skill.name,
253
+ skill.fromTemplate ? 'the template' : `${skill.level} skill`,
254
+ ]))}`;
100
255
  }
101
- function describePolicy(ctx, policy, changed) {
256
+ function describePolicy(ctx, policy, changed, source) {
257
+ var _a;
258
+ // Absent from an older host: say nothing rather than guess.
259
+ const unconfirmed = policy.accessConfirmed === false;
102
260
  const head = ctx.ui.result({
103
261
  title: changed
104
262
  ? `Policy updated for ${policy.slug} on ${policy.team.slug}`
105
263
  : `Policy of ${policy.slug} on ${policy.team.slug}`,
106
- tone: policy.editable ? 'ok' : 'warn',
264
+ tone: policy.editable && !unconfirmed ? 'ok' : 'warn',
107
265
  rows: [
108
266
  ['reads', policy.reads],
109
267
  ['writes', policy.writes],
110
268
  ['editable', policy.editable ? 'yes' : 'no — follows the template'],
111
269
  ],
112
- notes: policy.lockedReason ? [policy.lockedReason] : [],
270
+ notes: [
271
+ ...(policy.lockedReason ? [policy.lockedReason] : []),
272
+ ...(unconfirmed
273
+ ? [
274
+ `Not confirmed: until ${(_a = policy.runsAs) !== null && _a !== void 0 ? _a : 'the person it runs as'} confirms it may use their connections, it uses only what needs no confirmation (a looser policy drops a confirmation). They run: ${confirmCommand(policy.team.slug, policy.key, source)} — or, for the team's own agent, confirm on its page in the app`,
275
+ ]
276
+ : []),
277
+ ],
113
278
  });
114
279
  if (policy.tools.length === 0) {
115
280
  return `${head}\n\nNo tools yet: connect its integrations or MCP servers.`;
@@ -121,6 +286,31 @@ function describePolicy(ctx, policy, changed) {
121
286
  `${tool.decision === 'auto' ? 'on its own' : 'waits for approval'}${tool.overridden ? ' (set per tool)' : ''}`,
122
287
  ]))}`;
123
288
  }
289
+ /**
290
+ * The version `confirm` is about to approve — the one waiting on a held
291
+ * agent, else the one it runs — printed before it is sent, so the person
292
+ * confirms what they saw. Null when the team's agent has no version to name.
293
+ */
294
+ async function shownVersion(ctx, run, base, key) {
295
+ var _a;
296
+ var _b;
297
+ const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
298
+ method: 'GET',
299
+ path: base,
300
+ source: run.source,
301
+ }));
302
+ const agent = (_a = list.agents.find((entry) => entry.key === key)) === null || _a === void 0 ? void 0 : _a.agent;
303
+ if (!agent)
304
+ return null;
305
+ if (agent.held) {
306
+ ctx.log(`Confirming v${agent.held.waiting} of ${key} on ${list.team.slug}: ${describeHold(agent.held)}. It runs v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} until then.`);
307
+ return agent.held.waiting;
308
+ }
309
+ if (agent.version === null)
310
+ return null;
311
+ ctx.log(`Confirming ${key} v${agent.version} on ${list.team.slug} may use your connections.`);
312
+ return agent.version;
313
+ }
124
314
  function change(run, path, method, body) {
125
315
  return run.client.call((token) => call(run.host, token, TeamAgentChangeResultSchema, {
126
316
  method,
@@ -129,38 +319,149 @@ function change(run, path, method, body) {
129
319
  body,
130
320
  }));
131
321
  }
132
- function describeEntry(entry) {
133
- var _a, _b, _c;
322
+ function describeEntry(entry, team, source) {
323
+ var _a, _b, _c, _d, _e, _f, _g;
324
+ const readiness = agentReadiness(entry, { team, source });
134
325
  if (!entry.agent) {
135
- return `\n${entry.key} — ${entry.name}\n off · v${(_a = entry.publishedVersion) !== null && _a !== void 0 ? _a : '?'} published · turn on: ekanos teams agents enable <team> ${entry.key}`;
326
+ return `\n${entry.key} — ${entry.name}\n off · v${(_a = entry.publishedVersion) !== null && _a !== void 0 ? _a : '?'} published\n ${liveLine(readiness)} · Next: ${readiness.next}`;
136
327
  }
137
328
  const agent = entry.agent;
138
- const version = `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
329
+ const version = versionLabel(agent);
139
330
  const lines = [
140
331
  `\n${entry.key} — ${entry.name}`,
141
- ` ${agent.status} · ${version} · runs as ${(_c = agent.runsAs) !== null && _c !== void 0 ? _c : 'nobody'}${agent.accessConfirmed ? '' : ' · access not confirmed'}`,
332
+ ` ${agent.status} · ${version} · runs as ${(_b = agent.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}${agent.accessConfirmed ? '' : ` · access not confirmed (${(_c = agent.runsAs) !== null && _c !== void 0 ? _c : 'they'}: ekanos teams agents confirm ${team} ${entry.key})`}`,
333
+ ...(agent.held
334
+ ? [
335
+ ` ! held on v${(_d = agent.version) !== null && _d !== void 0 ? _d : '?'}: v${agent.held.waiting} ${describeHold(agent.held)}. It keeps running v${(_e = agent.version) !== null && _e !== void 0 ? _e : '?'} until ${(_f = agent.runsAs) !== null && _f !== void 0 ? _f : 'the person it runs as'} confirms: ${confirmCommand(team, entry.key, source)}`,
336
+ ]
337
+ : []),
142
338
  ` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
143
339
  ` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,
144
340
  ];
145
- if (agent.missing.length > 0) {
146
- lines.push(` missing: ${agent.missing.map((item) => `${item.name} (${item.kind === 'mcp' ? 'MCP server' : 'integration'} ${item.key})`).join(', ')}`);
147
- }
341
+ lines.push(...requirementLines(agent.requirements, agent.missing, team, source));
342
+ if (agent.draft)
343
+ lines.push(...draftLines(team, entry.key));
344
+ lines.push(...channelLines((_g = agent.channels) !== null && _g !== void 0 ? _g : [], team, source));
345
+ lines.push(` ${liveLine(readiness, agent)}${readiness.next ? ` · Next: ${readiness.next}` : ''}`);
148
346
  return lines.join('\n');
149
347
  }
150
- function describeChange(result, title) {
348
+ function versionLabel(agent) {
151
349
  var _a, _b, _c;
350
+ if (agent.draft)
351
+ return `draft v${(_a = agent.version) !== null && _a !== void 0 ? _a : '?'} (testing, unpublished)`;
352
+ if (agent.held)
353
+ return `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} (held, v${agent.held.waiting} waiting for confirmation)`;
354
+ return `v${(_c = agent.version) !== null && _c !== void 0 ? _c : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
355
+ }
356
+ /** What testing a draft on a team means, and the next step. */
357
+ function draftLines(team, key) {
358
+ return [
359
+ ' Only this team runs the draft, and only when started by hand: its triggers, schedules and hand-offs do not start it, and every write waits for approval.',
360
+ ` Test it: ekanos agents test ${key} --team ${team} --prompt "…" --follow. Publishing (ekanos agents publish ${key}) puts this team back to following.`,
361
+ ];
362
+ }
363
+ /**
364
+ * An older host ignores `draft` and would have turned on, or unpinned to,
365
+ * the published version instead. Say so rather than report a draft test
366
+ * that is not happening.
367
+ */
368
+ function requireDraftHost(result, verb) {
369
+ var _a;
370
+ if (result.draft === true)
371
+ return;
372
+ throw invalidStateError(`This host does not support testing a draft on one team: it ${verb} ${result.slug} on v${(_a = result.version) !== null && _a !== void 0 ? _a : '?'} ${result.pinned ? '(pinned)' : '(following)'} instead.`, `Check with "ekanos teams agents list ${result.team.slug}", and test once the host is updated.`);
373
+ }
374
+ /**
375
+ * What the agent still needs connected, each with why and the command that
376
+ * makes it; then any product working on another connection than the one its
377
+ * template names (the Source connection unusable, the team's own used).
378
+ */
379
+ export function requirementLines(requirements, missing, team, source) {
380
+ const missingLines = missing.flatMap((item) => {
381
+ const fix = requirementFix(item, team, source);
382
+ return [
383
+ ` ✗ missing: ${item.name} (${item.kind === 'mcp' ? 'MCP server' : 'integration'} ${item.key})${item.reason && item.reason !== 'not_connected' ? ` — ${REASON_WORDS[item.reason]}` : ''}`,
384
+ ...(fix ? [` → ${fix}`] : []),
385
+ ];
386
+ });
387
+ const fallbacks = requirements
388
+ .filter((item) => item.connected &&
389
+ item.reason !== undefined &&
390
+ item.reason !== null &&
391
+ item.reason !== 'not_connected')
392
+ .flatMap((item) => {
393
+ const fix = requirementFix(item, team, source);
394
+ return [
395
+ ` ! ${item.name} uses the team's own connection: ${REASON_WORDS[item.reason]}`,
396
+ ...(fix ? [` → ${fix}`] : []),
397
+ ];
398
+ });
399
+ return [...missingLines, ...fallbacks];
400
+ }
401
+ /**
402
+ * What the agent's triggers need installed before they can fire: missing
403
+ * ones first, each with the command that installs it. A trigger listed above
404
+ * with its channel missing here is one that will never start a run.
405
+ */
406
+ export function channelLines(channels, team, source) {
407
+ return channels.flatMap((channel) => { var _a; return channel.ready
408
+ ? [
409
+ channel.arrival === undefined || channel.arrival === 'install'
410
+ ? ` ✓ ${channel.name} installed — ${channel.triggers.join(', ')} can fire`
411
+ : ` ✓ ${channel.triggers.join(', ')} reachable (${reachedVia(channel)}${channel.lastDeliveryAt ? `, last delivery ${channel.lastDeliveryAt}` : ''}) — can fire`,
412
+ ]
413
+ : [
414
+ ` ✗ missing: ${(_a = channel.problem) !== null && _a !== void 0 ? _a : `${channel.name} not ready`} — ${channel.triggers.join(', ')} can never fire until it is`,
415
+ ` → ${fixLine(channelFix(channel, team, source))}`,
416
+ ]; });
417
+ }
418
+ function describeChange(result, title, source, options = {}) {
419
+ var _a, _b, _c, _d, _e, _f;
420
+ const covers = result.access ? describeAccess(result.access) : null;
152
421
  const lines = [
153
- `✓ ${title}`,
154
- ` ${result.status} · v${(_a = result.version) !== null && _a !== void 0 ? _a : '?'} ${result.pinned ? '(pinned)' : '(following)'} · runs as ${(_b = result.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}`,
422
+ `${options.confirmRequested && !result.accessConfirmed ? '!' : '✓'} ${title}`,
423
+ ` ${result.status} · ${versionLabel(result)} · runs as ${(_a = result.runsAs) !== null && _a !== void 0 ? _a : 'nobody'}`,
155
424
  ];
156
- if (!result.accessConfirmed) {
157
- lines.push(` ${(_c = result.runsAs) !== null && _c !== void 0 ? _c : 'The person it runs as'} confirms it may use their connections on the agent's page in the app.`);
425
+ if (result.accessConfirmed) {
426
+ if (covers) {
427
+ lines.push(result.advanced
428
+ ? ` Now allowed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`
429
+ : ` Confirmed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`);
430
+ }
431
+ if (result.held) {
432
+ lines.push(` Held on v${(_b = result.version) !== null && _b !== void 0 ? _b : '?'}: v${result.held.waiting} ${describeHold(result.held)}. ${(_c = result.runsAs) !== null && _c !== void 0 ? _c : 'The person it runs as'} moves it by confirming: ${confirmCommand(result.team.slug, result.key, source)}`);
433
+ }
158
434
  }
159
- if (result.missing.length > 0) {
160
- lines.push(` Still to connect: ${result.missing.map((item) => `${item.name} (${item.key})`).join(', ')}`);
435
+ else {
436
+ if (options.confirmRequested) {
437
+ // An older host ignores confirmAccess rather than refusing it.
438
+ lines.push(' This host did not record the confirmation: it may not support confirming from the CLI yet.');
439
+ }
440
+ lines.push(` Not confirmed: until ${(_d = result.runsAs) !== null && _d !== void 0 ? _d : 'the person it runs as'} confirms it may use their connections${covers ? ` (to ${covers})` : ''}, it uses only what needs no confirmation.`, ` → ${(_e = result.runsAs) !== null && _e !== void 0 ? _e : 'They'}, as themselves: ${confirmCommand(result.team.slug, result.key, source)}`);
161
441
  }
442
+ lines.push(...requirementLines([], result.missing, result.team.slug, source));
443
+ if (result.draft)
444
+ lines.push(...draftLines(result.team.slug, result.key));
445
+ lines.push(...channelLines((_f = result.channels) !== null && _f !== void 0 ? _f : [], result.team.slug, source));
162
446
  return lines.join('\n');
163
447
  }
448
+ /** What a confirmation covers, in words: whose connections, to what. */
449
+ export function describeAccess(access) {
450
+ if (access.scope === 'all')
451
+ return 'every tool of every product they connect';
452
+ if (access.scope === 'read_only')
453
+ return 'read from every product they connect';
454
+ const parts = [
455
+ ...access.products.map((product) => `${product.name} (every tool)`),
456
+ ...access.tools,
457
+ ];
458
+ return parts.length > 0
459
+ ? parts.join(', ')
460
+ : 'nothing yet (no products granted)';
461
+ }
462
+ function confirmCommand(team, key, source) {
463
+ return `ekanos teams agents confirm ${team} ${key} --source ${source}`;
464
+ }
164
465
  function expectOperands(run, count) {
165
466
  const extra = run.operands[count];
166
467
  if (extra !== undefined) {