@ekanos/cli 0.13.0 → 0.15.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 (173) 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.js +2 -2
  6. package/dist/apps-api.js.map +1 -1
  7. package/dist/auth/ekanos-api.d.ts +16 -2
  8. package/dist/auth/ekanos-api.js +101 -15
  9. package/dist/auth/ekanos-api.js.map +1 -1
  10. package/dist/auth/host-trust.d.ts +46 -0
  11. package/dist/auth/host-trust.js +79 -0
  12. package/dist/auth/host-trust.js.map +1 -0
  13. package/dist/auth/session.d.ts +10 -1
  14. package/dist/auth/session.js +28 -28
  15. package/dist/auth/session.js.map +1 -1
  16. package/dist/commands/agents-edit.d.ts +6 -2
  17. package/dist/commands/agents-edit.js +57 -26
  18. package/dist/commands/agents-edit.js.map +1 -1
  19. package/dist/commands/agents.d.ts +13 -2
  20. package/dist/commands/agents.js +140 -35
  21. package/dist/commands/agents.js.map +1 -1
  22. package/dist/commands/apps.d.ts +2 -0
  23. package/dist/commands/apps.js +16 -12
  24. package/dist/commands/apps.js.map +1 -1
  25. package/dist/commands/catalog.js +7 -6
  26. package/dist/commands/catalog.js.map +1 -1
  27. package/dist/commands/knowledge.d.ts +19 -0
  28. package/dist/commands/knowledge.js +119 -27
  29. package/dist/commands/knowledge.js.map +1 -1
  30. package/dist/commands/login.d.ts +4 -0
  31. package/dist/commands/login.js +30 -2
  32. package/dist/commands/login.js.map +1 -1
  33. package/dist/commands/logout.d.ts +9 -1
  34. package/dist/commands/logout.js +56 -7
  35. package/dist/commands/logout.js.map +1 -1
  36. package/dist/commands/publish.js +3 -3
  37. package/dist/commands/publish.js.map +1 -1
  38. package/dist/commands/reviewers.d.ts +2 -0
  39. package/dist/commands/reviewers.js +7 -3
  40. package/dist/commands/reviewers.js.map +1 -1
  41. package/dist/commands/routes.d.ts +2 -0
  42. package/dist/commands/routes.js +42 -9
  43. package/dist/commands/routes.js.map +1 -1
  44. package/dist/commands/runs.d.ts +13 -2
  45. package/dist/commands/runs.js +99 -16
  46. package/dist/commands/runs.js.map +1 -1
  47. package/dist/commands/scope-notice.d.ts +21 -0
  48. package/dist/commands/scope-notice.js +35 -0
  49. package/dist/commands/scope-notice.js.map +1 -0
  50. package/dist/commands/skills.d.ts +7 -1
  51. package/dist/commands/skills.js +80 -24
  52. package/dist/commands/skills.js.map +1 -1
  53. package/dist/commands/sources.d.ts +1 -1
  54. package/dist/commands/sources.js +126 -12
  55. package/dist/commands/sources.js.map +1 -1
  56. package/dist/commands/status.js +5 -4
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/commands/team-agent-readiness.d.ts +49 -0
  59. package/dist/commands/team-agent-readiness.js +308 -0
  60. package/dist/commands/team-agent-readiness.js.map +1 -0
  61. package/dist/commands/team-agents-agents.d.ts +24 -3
  62. package/dist/commands/team-agents-agents.js +314 -35
  63. package/dist/commands/team-agents-agents.js.map +1 -1
  64. package/dist/commands/team-agents-mcp.js +32 -3
  65. package/dist/commands/team-agents-mcp.js.map +1 -1
  66. package/dist/commands/team-agents-triggers.js +230 -55
  67. package/dist/commands/team-agents-triggers.js.map +1 -1
  68. package/dist/commands/team-agents.d.ts +3 -1
  69. package/dist/commands/team-agents.js +27 -7
  70. package/dist/commands/team-agents.js.map +1 -1
  71. package/dist/commands/teams-channel-install.d.ts +24 -0
  72. package/dist/commands/teams-channel-install.js +94 -0
  73. package/dist/commands/teams-channel-install.js.map +1 -0
  74. package/dist/commands/teams-connect.d.ts +41 -0
  75. package/dist/commands/teams-connect.js +212 -57
  76. package/dist/commands/teams-connect.js.map +1 -1
  77. package/dist/commands/teams-events.d.ts +12 -0
  78. package/dist/commands/teams-events.js +138 -0
  79. package/dist/commands/teams-events.js.map +1 -0
  80. package/dist/commands/teams-onboard.d.ts +11 -3
  81. package/dist/commands/teams-onboard.js +60 -7
  82. package/dist/commands/teams-onboard.js.map +1 -1
  83. package/dist/commands/teams-overview.d.ts +11 -0
  84. package/dist/commands/teams-overview.js +160 -0
  85. package/dist/commands/teams-overview.js.map +1 -0
  86. package/dist/commands/teams-scope.d.ts +10 -0
  87. package/dist/commands/teams-scope.js +109 -0
  88. package/dist/commands/teams-scope.js.map +1 -0
  89. package/dist/commands/teams.d.ts +4 -2
  90. package/dist/commands/teams.js +113 -14
  91. package/dist/commands/teams.js.map +1 -1
  92. package/dist/commands/upgrade.js +12 -2
  93. package/dist/commands/upgrade.js.map +1 -1
  94. package/dist/commands/use.js +2 -2
  95. package/dist/commands/use.js.map +1 -1
  96. package/dist/commands/whoami.js +1 -1
  97. package/dist/commands/whoami.js.map +1 -1
  98. package/dist/connections-api.js +1 -1
  99. package/dist/connections-api.js.map +1 -1
  100. package/dist/delegate.js +11 -4
  101. package/dist/delegate.js.map +1 -1
  102. package/dist/harness-scaffold.js +12 -0
  103. package/dist/harness-scaffold.js.map +1 -1
  104. package/dist/index.d.ts +6 -0
  105. package/dist/index.js +682 -167
  106. package/dist/index.js.map +1 -1
  107. package/dist/knowledge-api.d.ts +46 -0
  108. package/dist/knowledge-api.js +32 -1
  109. package/dist/knowledge-api.js.map +1 -1
  110. package/dist/open-url.d.ts +16 -0
  111. package/dist/open-url.js +73 -0
  112. package/dist/open-url.js.map +1 -0
  113. package/dist/parse-argv.d.ts +2 -0
  114. package/dist/parse-argv.js.map +1 -1
  115. package/dist/publish-api.d.ts +2 -1
  116. package/dist/publish-api.js +4 -3
  117. package/dist/publish-api.js.map +1 -1
  118. package/dist/pull-write.d.ts +27 -0
  119. package/dist/pull-write.js +60 -0
  120. package/dist/pull-write.js.map +1 -0
  121. package/dist/routes-api.d.ts +3 -0
  122. package/dist/routes-api.js +9 -4
  123. package/dist/routes-api.js.map +1 -1
  124. package/dist/runs-api.d.ts +7 -1
  125. package/dist/runs-api.js +21 -6
  126. package/dist/runs-api.js.map +1 -1
  127. package/dist/safe-fs.d.ts +2 -0
  128. package/dist/safe-fs.js +12 -6
  129. package/dist/safe-fs.js.map +1 -1
  130. package/dist/secret-file.d.ts +17 -0
  131. package/dist/secret-file.js +69 -0
  132. package/dist/secret-file.js.map +1 -0
  133. package/dist/skills-api.d.ts +10 -2
  134. package/dist/skills-api.js +37 -2
  135. package/dist/skills-api.js.map +1 -1
  136. package/dist/source-products-api.d.ts +4 -0
  137. package/dist/source-products-api.js +14 -4
  138. package/dist/source-products-api.js.map +1 -1
  139. package/dist/source-target.js +2 -1
  140. package/dist/source-target.js.map +1 -1
  141. package/dist/sources-api.d.ts +2 -1
  142. package/dist/sources-api.js +3 -2
  143. package/dist/sources-api.js.map +1 -1
  144. package/dist/team-connect-api.d.ts +44 -2
  145. package/dist/team-connect-api.js +19 -7
  146. package/dist/team-connect-api.js.map +1 -1
  147. package/dist/teams-api.d.ts +41 -1
  148. package/dist/teams-api.js +95 -19
  149. package/dist/teams-api.js.map +1 -1
  150. package/dist/toolchain-api.d.ts +9 -0
  151. package/dist/toolchain-api.js +17 -2
  152. package/dist/toolchain-api.js.map +1 -1
  153. package/dist/toolchain-resolve.d.ts +3 -0
  154. package/dist/toolchain-resolve.js +15 -1
  155. package/dist/toolchain-resolve.js.map +1 -1
  156. package/dist/toolchain.d.ts +6 -0
  157. package/dist/toolchain.js +19 -0
  158. package/dist/toolchain.js.map +1 -1
  159. package/dist/update-notice.js +2 -1
  160. package/dist/update-notice.js.map +1 -1
  161. package/package.json +2 -2
  162. package/templates/AGENTS.md.tmpl +6 -1
  163. package/templates/claude-skill.md.tmpl +5 -0
  164. package/templates/package.json.tmpl +4 -4
  165. package/templates/skills/build-agent/SKILL.md +104 -17
  166. package/templates/skills/build-agent/references/agent-json.md +4 -2
  167. package/templates/skills/build-agent/references/rollout.md +23 -4
  168. package/templates/skills/build-agent/references/set-up-an-integration.md +55 -7
  169. package/templates/skills/build-agent/references/skills.md +20 -1
  170. package/templates/skills/build-agent/references/triggers.md +47 -11
  171. package/templates/skills/build-integration/references/widget-design.md +3 -3
  172. package/templates/skills/ekanos-platform/SKILL.md +45 -16
  173. 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;;;;;;;;;;;GAWG;AAEH,MAAM,GAAG,GAAG,iBAAiB,CAAC;AAqB9B,MAAM,UAAU,cAAc,CAC5B,KAAqB,EACrB,MAAuB;;;IAEvB,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC;QACxB,KAAK;QACL,IAAI,QAAE,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,GAAG,mCAAI,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED;;;;GAIG;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,KAAK,CAAC,IAAI,CAAC;YACT,OAAO,EAAE,sCAAsC;YAC/C,qEAAqE;YACrE,6CAA6C;YAC7C,GAAG,EAAE,GAAG,GAAG,yBAAyB,IAAI,IAAI,KAAK,CAAC,GAAG,aAAa,MAAM,sDAAsD,KAAK,CAAC,IAAI,WAAW;SACpJ,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,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,SAAyB;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,OAAO,SAAS,CAAC,IAAI;QACnB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,cAAc,IAAI,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAC7D,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,IAAI,MAAA,KAAK,CAAC,OAAO,mCAAI,GAAG,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,GAAG;QACzE,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,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,KAAK,QAAQ,CAAC,SAAS,CAAC,EAAE;QAC1B,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 someone who sets it up (a team manager or the Source\n * admin, plan 247.2), at least one trigger on, and every trigger's events\n * able to reach it. Each gap is a step with one fix, in the order they have\n * to be done; the first step's fix is \"Next\". A publish holds no team, so\n * there is no update waiting.\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 /** The first step's fix; null when there is none. */\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 return {\n live: steps.length === 0,\n steps,\n next: steps[0]?.fix ?? null,\n };\n}\n\n/**\n * What a newer version adds over the one a team runs, in words (a publish's\n * report of the teams pinned to another version):\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 steps.push({\n problem: 'nobody has confirmed what it may use',\n // Whoever sets it up confirms, as themselves: the Source admin here,\n // or a team manager in the app (plan 247.2).\n fix: `${CLI} teams agents confirm ${team} ${entry.key} --source ${source} (or a team manager 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/** \"Live: yes\" or \"Live: no — N steps left\". */\nexport function liveLine(readiness: AgentReadiness): string {\n const left = readiness.steps.length;\n return readiness.live\n ? 'Live: yes'\n : `Live: no — ${left} step${left === 1 ? '' : 's'} left`;\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 : `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 return [\n head,\n ...products,\n ...(agent.triggers.length > 0 ? triggers : [` ${pad('triggers')} none`]),\n ` ${liveLine(readiness)}`,\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`) records the caller's own
11
+ * confirmation that it may use its connections in runs no one watches:
12
+ * whoever sets an agent up confirms it (plan 247.2), never a member.
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, 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`) records the caller's own
12
+ * confirmation that it may use its connections in runs no one watches:
13
+ * whoever sets an agent up confirms it (plan 247.2), never a member.
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,128 @@ 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 what it may use' : ''}`, 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, `You confirmed what ${result.slug} on ${result.team.slug} may use`, run.source, { confirmRequested: true }));
44
70
  }
45
71
  case 'disable': {
46
72
  expectOperands(run, 2);
73
+ if (!run.args.yes) {
74
+ 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`);
75
+ }
47
76
  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}`));
77
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned off ${result.slug} for ${result.team.slug}`, run.source));
49
78
  }
50
79
  case 'pin': {
80
+ if (((_c = run.args.flags) === null || _c === void 0 ? void 0 : _c.draft) === true) {
81
+ expectOperands(run, 2);
82
+ const result = await change(run, `${path}/pin`, 'PUT', {
83
+ version: null,
84
+ draft: true,
85
+ });
86
+ requireDraftHost(result, 'pinned');
87
+ 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));
88
+ }
51
89
  expectOperands(run, 3);
52
90
  const version = Number(run.operands[2]);
53
91
  if (!Number.isInteger(version) || version < 1) {
54
92
  throw usageError(run.operands[2]
55
93
  ? `"${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.`);
94
+ : '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
95
  }
58
96
  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}`));
97
+ 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
98
  }
61
99
  case 'unpin': {
62
100
  expectOperands(run, 2);
63
101
  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}`));
102
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}`, run.source));
65
103
  }
66
104
  case 'policy':
67
105
  return policy(ctx, run, team, key, `${path}/policy`);
106
+ case 'skills':
107
+ return skills(ctx, run, team, key, `${path}/skills`);
68
108
  default:
69
109
  throw usageError(`Unknown teams agents subcommand "${run.verb}".`, usageFor('agents'));
70
110
  }
71
111
  }
112
+ /**
113
+ * One agent on one team: each product and whose connection it acts through,
114
+ * each trigger and how its events reach the agent (with the last event and
115
+ * the last run), access, "Live: yes/no" and exactly one Next. Reads the
116
+ * team's agents, then its recent runs and events; a host without the
117
+ * activity reads still answers the rest.
118
+ */
119
+ async function show(ctx, run, base, key) {
120
+ var _a, _b, _c;
121
+ const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
122
+ method: 'GET',
123
+ path: base,
124
+ source: run.source,
125
+ }));
126
+ const entry = list.agents.find((candidate) => candidate.key === key);
127
+ if (!entry) {
128
+ throw notFoundError(`No agent "${key}" is provided for ${list.team.slug}.`, `"ekanos teams agents list ${list.team.slug}" lists the agents provided for it.`);
129
+ }
130
+ const target = { team: list.team.slug, source: run.source };
131
+ const readiness = agentReadiness(entry, target);
132
+ const [runs, events] = entry.agent
133
+ ? await Promise.all([
134
+ activity(ctx, 'runs', () => run.client.call((token) => call(run.host, token, AgentRunListSchema, {
135
+ method: 'GET',
136
+ path: `/api/partner/teams/${encodeURIComponent(target.team)}/runs?agent=${encodeURIComponent(key)}`,
137
+ source: run.source,
138
+ }))),
139
+ entry.agent.triggers.some((trigger) => trigger.eventId)
140
+ ? activity(ctx, 'events', () => run.client.call((token) => listTeamEvents(run.host, token, { source: run.source, team: target.team }, { limit: 100 })))
141
+ : Promise.resolve(null),
142
+ ])
143
+ : [null, null];
144
+ return ctx.succeed({
145
+ host: run.host,
146
+ team: list.team,
147
+ agent: entry,
148
+ readiness,
149
+ lastRun: (_a = runs === null || runs === void 0 ? void 0 : runs.runs[0]) !== null && _a !== void 0 ? _a : null,
150
+ recentEvents: events
151
+ ? events.events.filter((event) => { var _a; return (_a = entry.agent) === null || _a === void 0 ? void 0 : _a.triggers.some((trigger) => trigger.eventId === event.eventId); })
152
+ : null,
153
+ }, describeAgentReadiness(entry, target, readiness, {
154
+ runs: (_b = runs === null || runs === void 0 ? void 0 : runs.runs) !== null && _b !== void 0 ? _b : null,
155
+ events: (_c = events === null || events === void 0 ? void 0 : events.events) !== null && _c !== void 0 ? _c : null,
156
+ }, list.scope));
157
+ }
158
+ /** A read `show` can do without: on failure, say so and carry on. */
159
+ async function activity(ctx, what, read) {
160
+ try {
161
+ return await read();
162
+ }
163
+ catch (error) {
164
+ ctx.log(`Could not read the team's recent ${what}: ${error instanceof Error ? error.message : String(error)}`);
165
+ return null;
166
+ }
167
+ }
72
168
  async function policy(ctx, run, team, key, path) {
169
+ var _a;
73
170
  const [action, tool, decision] = run.operands.slice(2);
74
171
  const change = {};
75
172
  const reads = approvalFlag(run, 'reads');
@@ -95,21 +192,86 @@ async function policy(ctx, run, team, key, path) {
95
192
  throw usageError(`Unknown policy action "${action}".`, usageFor('agents'));
96
193
  }
97
194
  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));
195
+ const confirmAccess = ((_a = run.args.flags) === null || _a === void 0 ? void 0 : _a['confirm-access']) === true;
196
+ if (confirmAccess && !writing) {
197
+ throw usageError('--confirm-access goes with a policy change.', `To confirm on its own: "ekanos teams agents confirm ${team} ${key}".`);
198
+ }
199
+ const result = await run.client.call((token) => call(run.host, token, TeamAgentPolicySchema, Object.assign({ method: writing ? 'PUT' : 'GET', path, source: run.source }, (writing
200
+ ? { body: Object.assign(Object.assign({}, change), (confirmAccess ? { confirmAccess } : {})) }
201
+ : {}))));
202
+ return ctx.succeed(Object.assign({ host: run.host }, result), describePolicy(ctx, result, writing, run.source));
203
+ }
204
+ /**
205
+ * `teams agents skills <team> <key> [add|remove <skill>]` — the skills the
206
+ * team's agent reads. A provided agent takes the team's own only where its
207
+ * template allows (`teamCustomization.skills`); its template's stay.
208
+ */
209
+ async function skills(ctx, run, team, key, path) {
210
+ const [action, slug, extra] = run.operands.slice(2);
211
+ if (extra !== undefined) {
212
+ throw usageError(`Unexpected argument "${extra}".`, usageFor('agents'));
213
+ }
214
+ let change = null;
215
+ if (action === 'add' || action === 'remove') {
216
+ if (!slug) {
217
+ 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.`);
218
+ }
219
+ change = { [action]: [slug.trim().toLowerCase()] };
220
+ }
221
+ else if (action !== undefined) {
222
+ throw usageError(`Unknown skills action "${action}".`, usageFor('agents'));
223
+ }
224
+ 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 } : {}))));
225
+ return ctx.succeed(Object.assign({ host: run.host }, result), describeSkills(ctx, result, change));
100
226
  }
101
- function describePolicy(ctx, policy, changed) {
227
+ function describeSkills(ctx, result, change) {
228
+ const [verb, slug] = (change === null || change === void 0 ? void 0 : change.add)
229
+ ? ['Attached', change.add[0]]
230
+ : (change === null || change === void 0 ? void 0 : change.remove)
231
+ ? ['Detached', change.remove[0]]
232
+ : [null, null];
233
+ const head = ctx.ui.result({
234
+ title: verb
235
+ ? `${verb} ${slug} ${verb === 'Attached' ? 'to' : 'from'} ${result.slug} on ${result.team.slug}`
236
+ : `Skills of ${result.slug} on ${result.team.slug}`,
237
+ tone: result.editable ? 'ok' : 'warn',
238
+ rows: [
239
+ [
240
+ 'team skills',
241
+ result.editable ? 'allowed' : 'no — follows the template',
242
+ ],
243
+ ],
244
+ notes: result.lockedReason ? [result.lockedReason] : [],
245
+ });
246
+ if (result.skills.length === 0)
247
+ return `${head}\n\nNo skills attached.`;
248
+ return `${head}\n\n${ctx.ui.table(['skill', 'name', 'from'], result.skills.map((skill) => [
249
+ skill.slug,
250
+ skill.name,
251
+ skill.fromTemplate ? 'the template' : `${skill.level} skill`,
252
+ ]))}`;
253
+ }
254
+ function describePolicy(ctx, policy, changed, source) {
255
+ // Absent from an older host: say nothing rather than guess.
256
+ const unconfirmed = policy.accessConfirmed === false;
102
257
  const head = ctx.ui.result({
103
258
  title: changed
104
259
  ? `Policy updated for ${policy.slug} on ${policy.team.slug}`
105
260
  : `Policy of ${policy.slug} on ${policy.team.slug}`,
106
- tone: policy.editable ? 'ok' : 'warn',
261
+ tone: policy.editable && !unconfirmed ? 'ok' : 'warn',
107
262
  rows: [
108
263
  ['reads', policy.reads],
109
264
  ['writes', policy.writes],
110
265
  ['editable', policy.editable ? 'yes' : 'no — follows the template'],
111
266
  ],
112
- notes: policy.lockedReason ? [policy.lockedReason] : [],
267
+ notes: [
268
+ ...(policy.lockedReason ? [policy.lockedReason] : []),
269
+ ...(unconfirmed
270
+ ? [
271
+ `Not confirmed: until you or one of the team's agent managers confirms what it may use, it uses only what needs no confirmation (a looser policy drops a confirmation). Confirm it as yourself with --confirm-access on the change, or for a provided agent ${confirmCommand(policy.team.slug, policy.key, source)}; a team manager can also confirm on its page in the app`,
272
+ ]
273
+ : []),
274
+ ],
113
275
  });
114
276
  if (policy.tools.length === 0) {
115
277
  return `${head}\n\nNo tools yet: connect its integrations or MCP servers.`;
@@ -121,6 +283,24 @@ function describePolicy(ctx, policy, changed) {
121
283
  `${tool.decision === 'auto' ? 'on its own' : 'waits for approval'}${tool.overridden ? ' (set per tool)' : ''}`,
122
284
  ]))}`;
123
285
  }
286
+ /**
287
+ * The version `confirm` is about to approve — the one it runs — printed
288
+ * before it is sent, so the person confirms what they saw. Null when the
289
+ * team's agent has no version to name.
290
+ */
291
+ async function shownVersion(ctx, run, base, key) {
292
+ var _a;
293
+ const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
294
+ method: 'GET',
295
+ path: base,
296
+ source: run.source,
297
+ }));
298
+ const agent = (_a = list.agents.find((entry) => entry.key === key)) === null || _a === void 0 ? void 0 : _a.agent;
299
+ if (!agent || agent.version === null)
300
+ return null;
301
+ ctx.log(`Confirming what ${key} v${agent.version} on ${list.team.slug} may use${agent.runsAs ? ` (it runs as ${agent.runsAs})` : ''}.`);
302
+ return agent.version;
303
+ }
124
304
  function change(run, path, method, body) {
125
305
  return run.client.call((token) => call(run.host, token, TeamAgentChangeResultSchema, {
126
306
  method,
@@ -129,38 +309,137 @@ function change(run, path, method, body) {
129
309
  body,
130
310
  }));
131
311
  }
132
- function describeEntry(entry) {
312
+ function describeEntry(entry, team, source) {
133
313
  var _a, _b, _c;
314
+ const readiness = agentReadiness(entry, { team, source });
134
315
  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}`;
316
+ 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
317
  }
137
318
  const agent = entry.agent;
138
- const version = `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
319
+ const version = versionLabel(agent);
139
320
  const lines = [
140
321
  `\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'}`,
322
+ ` ${agent.status} · ${version} · runs as ${(_b = agent.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}${agent.accessConfirmed ? '' : ` · access not confirmed (${confirmCommand(team, entry.key, source)})`}`,
142
323
  ` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
143
324
  ` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,
144
325
  ];
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
- }
326
+ lines.push(...requirementLines(agent.requirements, agent.missing, team, source));
327
+ if (agent.draft)
328
+ lines.push(...draftLines(team, entry.key));
329
+ lines.push(...channelLines((_c = agent.channels) !== null && _c !== void 0 ? _c : [], team, source));
330
+ lines.push(` ${liveLine(readiness)}${readiness.next ? ` · Next: ${readiness.next}` : ''}`);
148
331
  return lines.join('\n');
149
332
  }
150
- function describeChange(result, title) {
151
- var _a, _b, _c;
333
+ function versionLabel(agent) {
334
+ var _a, _b;
335
+ if (agent.draft)
336
+ return `draft v${(_a = agent.version) !== null && _a !== void 0 ? _a : '?'} (testing, unpublished)`;
337
+ return `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
338
+ }
339
+ /** What testing a draft on a team means, and the next step. */
340
+ function draftLines(team, key) {
341
+ return [
342
+ ' 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.',
343
+ ` Test it: ekanos agents test ${key} --team ${team} --prompt "…" --follow. Publishing (ekanos agents publish ${key}) puts this team back to following.`,
344
+ ];
345
+ }
346
+ /**
347
+ * An older host ignores `draft` and would have turned on, or unpinned to,
348
+ * the published version instead. Say so rather than report a draft test
349
+ * that is not happening.
350
+ */
351
+ function requireDraftHost(result, verb) {
352
+ var _a;
353
+ if (result.draft === true)
354
+ return;
355
+ 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.`);
356
+ }
357
+ /**
358
+ * What the agent still needs connected, each with why and the command that
359
+ * makes it; then any product working on another connection than the one its
360
+ * template names (the Source connection unusable, the team's own used).
361
+ */
362
+ export function requirementLines(requirements, missing, team, source) {
363
+ const missingLines = missing.flatMap((item) => {
364
+ const fix = requirementFix(item, team, source);
365
+ return [
366
+ ` ✗ missing: ${item.name} (${item.kind === 'mcp' ? 'MCP server' : 'integration'} ${item.key})${item.reason && item.reason !== 'not_connected' ? ` — ${REASON_WORDS[item.reason]}` : ''}`,
367
+ ...(fix ? [` → ${fix}`] : []),
368
+ ];
369
+ });
370
+ const fallbacks = requirements
371
+ .filter((item) => item.connected &&
372
+ item.reason !== undefined &&
373
+ item.reason !== null &&
374
+ item.reason !== 'not_connected')
375
+ .flatMap((item) => {
376
+ const fix = requirementFix(item, team, source);
377
+ return [
378
+ ` ! ${item.name} uses the team's own connection: ${REASON_WORDS[item.reason]}`,
379
+ ...(fix ? [` → ${fix}`] : []),
380
+ ];
381
+ });
382
+ return [...missingLines, ...fallbacks];
383
+ }
384
+ /**
385
+ * What the agent's triggers need installed before they can fire: missing
386
+ * ones first, each with the command that installs it. A trigger listed above
387
+ * with its channel missing here is one that will never start a run.
388
+ */
389
+ export function channelLines(channels, team, source) {
390
+ return channels.flatMap((channel) => { var _a; return channel.ready
391
+ ? [
392
+ channel.arrival === undefined || channel.arrival === 'install'
393
+ ? ` ✓ ${channel.name} installed — ${channel.triggers.join(', ')} can fire`
394
+ : ` ✓ ${channel.triggers.join(', ')} reachable (${reachedVia(channel)}${channel.lastDeliveryAt ? `, last delivery ${channel.lastDeliveryAt}` : ''}) — can fire`,
395
+ ]
396
+ : [
397
+ ` ✗ missing: ${(_a = channel.problem) !== null && _a !== void 0 ? _a : `${channel.name} not ready`} — ${channel.triggers.join(', ')} can never fire until it is`,
398
+ ` → ${fixLine(channelFix(channel, team, source))}`,
399
+ ]; });
400
+ }
401
+ function describeChange(result, title, source, options = {}) {
402
+ var _a, _b;
403
+ const covers = result.access ? describeAccess(result.access) : null;
152
404
  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'}`,
405
+ `${options.confirmRequested && !result.accessConfirmed ? '!' : '✓'} ${title}`,
406
+ ` ${result.status} · ${versionLabel(result)} · runs as ${(_a = result.runsAs) !== null && _a !== void 0 ? _a : 'nobody'}`,
155
407
  ];
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.`);
408
+ if (result.accessConfirmed) {
409
+ if (covers) {
410
+ lines.push(` Confirmed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`);
411
+ }
158
412
  }
159
- if (result.missing.length > 0) {
160
- lines.push(` Still to connect: ${result.missing.map((item) => `${item.name} (${item.key})`).join(', ')}`);
413
+ else {
414
+ if (options.confirmRequested) {
415
+ // An older host ignores confirmAccess rather than refusing it.
416
+ lines.push(' This host did not record the confirmation: it may not support confirming from the CLI yet.');
417
+ }
418
+ lines.push(` Not confirmed: until you or one of the team's agent managers confirms what it may use${covers ? ` (${result.runsAs ? `${result.runsAs}'s` : 'its'} connections, to ${covers})` : ''}, it uses only what needs no confirmation.`, ` → ${confirmCommand(result.team.slug, result.key, source)}`);
161
419
  }
420
+ lines.push(...requirementLines([], result.missing, result.team.slug, source));
421
+ if (result.draft)
422
+ lines.push(...draftLines(result.team.slug, result.key));
423
+ lines.push(...channelLines((_b = result.channels) !== null && _b !== void 0 ? _b : [], result.team.slug, source));
162
424
  return lines.join('\n');
163
425
  }
426
+ /** What a confirmation covers, in words: whose connections, to what. */
427
+ export function describeAccess(access) {
428
+ if (access.scope === 'all')
429
+ return 'every tool of every product they connect';
430
+ if (access.scope === 'read_only')
431
+ return 'read from every product they connect';
432
+ const parts = [
433
+ ...access.products.map((product) => `${product.name} (every tool)`),
434
+ ...access.tools,
435
+ ];
436
+ return parts.length > 0
437
+ ? parts.join(', ')
438
+ : 'nothing yet (no products granted)';
439
+ }
440
+ function confirmCommand(team, key, source) {
441
+ return `ekanos teams agents confirm ${team} ${key} --source ${source}`;
442
+ }
164
443
  function expectOperands(run, count) {
165
444
  const extra = run.operands[count];
166
445
  if (extra !== undefined) {