@ekanos/cli 0.10.0 → 0.11.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 (57) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/agents-edit.d.ts +49 -0
  3. package/dist/commands/agents-edit.js +385 -0
  4. package/dist/commands/agents-edit.js.map +1 -0
  5. package/dist/commands/agents.d.ts +24 -1
  6. package/dist/commands/agents.js +117 -8
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/reviewers.d.ts +21 -0
  9. package/dist/commands/reviewers.js +162 -0
  10. package/dist/commands/reviewers.js.map +1 -0
  11. package/dist/commands/runs.d.ts +42 -0
  12. package/dist/commands/runs.js +362 -0
  13. package/dist/commands/runs.js.map +1 -0
  14. package/dist/commands/skills.d.ts +60 -0
  15. package/dist/commands/skills.js +397 -0
  16. package/dist/commands/skills.js.map +1 -0
  17. package/dist/commands/team-agents-agents.d.ts +9 -0
  18. package/dist/commands/team-agents-agents.js +188 -0
  19. package/dist/commands/team-agents-agents.js.map +1 -0
  20. package/dist/commands/team-agents-mcp.d.ts +4 -0
  21. package/dist/commands/team-agents-mcp.js +218 -0
  22. package/dist/commands/team-agents-mcp.js.map +1 -0
  23. package/dist/commands/team-agents-triggers.d.ts +12 -0
  24. package/dist/commands/team-agents-triggers.js +251 -0
  25. package/dist/commands/team-agents-triggers.js.map +1 -0
  26. package/dist/commands/team-agents.d.ts +31 -0
  27. package/dist/commands/team-agents.js +71 -0
  28. package/dist/commands/team-agents.js.map +1 -0
  29. package/dist/commands/teams-onboard.d.ts +51 -0
  30. package/dist/commands/teams-onboard.js +261 -0
  31. package/dist/commands/teams-onboard.js.map +1 -0
  32. package/dist/commands/teams.d.ts +16 -1
  33. package/dist/commands/teams.js +22 -3
  34. package/dist/commands/teams.js.map +1 -1
  35. package/dist/index.js +197 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/reviewers-api.d.ts +33 -0
  38. package/dist/reviewers-api.js +81 -0
  39. package/dist/reviewers-api.js.map +1 -0
  40. package/dist/runs-api.d.ts +34 -0
  41. package/dist/runs-api.js +112 -0
  42. package/dist/runs-api.js.map +1 -0
  43. package/dist/skills-api.d.ts +28 -0
  44. package/dist/skills-api.js +104 -0
  45. package/dist/skills-api.js.map +1 -0
  46. package/dist/teams-api.d.ts +45 -3
  47. package/dist/teams-api.js +72 -3
  48. package/dist/teams-api.js.map +1 -1
  49. package/package.json +2 -2
  50. package/templates/package.json.tmpl +4 -4
  51. package/templates/skills/build-agent/SKILL.md +90 -8
  52. package/templates/skills/build-agent/references/agent-json.md +78 -2
  53. package/templates/skills/build-agent/references/rollout.md +9 -1
  54. package/templates/skills/build-agent/references/set-up-an-integration.md +2 -1
  55. package/templates/skills/build-agent/references/skills.md +78 -0
  56. package/templates/skills/build-agent/references/triggers.md +25 -5
  57. package/templates/skills/ekanos-platform/SKILL.md +108 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewers.js","sourceRoot":"","sources":["../../src/commands/reviewers.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,oBAAoB,EACpB,cAAc,EACd,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAEL,WAAW,EACX,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAU,CAAC;AAGxE,MAAM,OAAO,GAA6B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAa7D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAe,EACf,IAAmB;;;IAEnB,MAAM,CAAC,aAAa,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;IAC7D,MAAM,UAAU,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAElD,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACtD,MAAM,UAAU,CACd,oCAAoC,EACpC,8CAA8C,CAC/C,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,UAAU,CACd,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,EACpC,gCAAgC,CACjC,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,KAAK,GACT,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,IAAI,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1C,MAAM,UAAU,CACd,oCAAoC,EACpC,gCAAgC,KAAK,wDAAwD,CAC9F,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;QAC3D,UAAU,EAAE,IAAI,CAAC,GAAG;KACrB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CACxC,GAAG,EACH,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,EACnC,IAAI,CACL,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE/B,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACvC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CACvC,CAAC;QACF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;gBACZ,KAAK,EAAE,mBAAmB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;gBAC5C,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE;oBACL,mEAAmE;oBACnE,0DAA0D;iBAC3D;aACF,CAAC,CACH,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,IAAI,GACzB;YACE,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC/C,GAAG,CAAC,EAAE,CAAC,KAAK,CACV,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAChC;SACF,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,KAAK,KAAK,IAAI,KAAK,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACzC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,kBACjC,KAAK;YACL,KAAK,IACF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACzB,CACH,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,MAAM,GAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;YACZ,KAAK,EAAE,MAAM,CAAC,OAAO;gBACnB,CAAC,CAAC,SAAS,GAAG,CAAC,QAAQ,CAAC,gBAAgB;gBACxC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,gCAAgC;YACpD,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;YACpC,IAAI,EAAE;gBACJ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAClB,CAAC,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;aAChC;YACD,KAAK,EAAE;gBACL,QAAQ,CAAC,KAAK,KAAK,QAAQ;oBACzB,CAAC,CAAC,iFAAiF;oBACnF,CAAC,CAAC,WAAW,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,IAAI,mCAAI,UAAU,mEAAmE;aACpH;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACzC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,kBACpC,KAAK,IACF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EACzB,CACH,CAAC;IACF,OAAO,GAAG,CAAC,OAAO,iBACd,IAAI,EAAE,GAAG,CAAC,IAAI,IAAK,MAAM,GAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;QACZ,KAAK,EAAE,WAAW,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QACvD,IAAI,EAAE;YACJ,CAAC,QAAQ,EAAE,MAAM,CAAC;YAClB;gBACE,SAAS;gBACT,GAAG,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;aAC7D;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,QAAwB;;;IAC3C,OAAO;cACL,QAAQ,CAAC,KAAK,mCAAI,QAAQ,CAAC,MAAM;cACjC,QAAQ,CAAC,IAAI,mCAAI,GAAG;QACpB,QAAQ,CAAC,KAAK;cACd,MAAA,QAAQ,CAAC,IAAI,0CAAE,IAAI,mCAAI,GAAG;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,QAAwB;IAC1C,OAAO,QAAQ,CAAC,KAAK,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI;QAC/C,CAAC,CAAC,QAAQ,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG;QACtD,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED,SAAS,GAAG,CAAC,QAAwB;;IACnC,mBAAO,QAAQ,CAAC,KAAK,mCAAI,QAAQ,CAAC,IAAI,mCAAI,QAAQ,CAAC,MAAM,CAAC;AAC5D,CAAC;AAED,MAAM,eAAe;IACnB,YACmB,GAAoB,EAC7B,OAAsB;mBADb,GAAG;uBACZ,OAAO;IACd,CAAC;IAEJ,KAAK,CAAC,IAAI,CACR,IAA6D;QAE7D,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAClD,IAAI,MAAM,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAClE,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QAC/C,MAAM,iBAAiB,CACrB,mBAAmB,IAAI,CAAC,GAAG,CAAC,IAAI,0CAA0C,EAC1E,4BAA4B,IAAI,CAAC,GAAG,CAAC,IAAI,cAAc,CACxD,CAAC;IACJ,CAAC;CACF;AAED,SAAS,eAAe,CAAC,KAAyB;IAChD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IACnE,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,UAAU,CACd,KAAK;QACH,CAAC,CAAC,iCAAiC,KAAK,IAAI;QAC5C,CAAC,CAAC,+BAA+B,EACnC,uJAAuJ,CACxJ,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB,EAAE,UAA4B;IAC3E,MAAM,KAAK,GAAG,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,GAAG,WAAW,EAAE,CAAC;IAC1C,IAAI,KAAK,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3D,MAAM,UAAU,CACd,KAAK;QACH,CAAC,CAAC,IAAI,KAAK,4BAA4B;QACvC,CAAC,CAAC,6BAA6B,EACjC,UAAU,KAAK,KAAK;QAClB,CAAC,CAAC,6DAA6D;QAC/D,CAAC,CAAC,4CAA4C,CACjD,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,UAAU,CACd,IAAI,KAAK,uBAAuB,EAChC,0DAA0D,CAC3D,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,KAAyB,EACzB,KAAa,EACb,IAAwB;IAExB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,MAAK,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,GAAG,WAAW,EAAE,CAAA,CAAC,CAAC;IAC7E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,UAAU,CACd,KAAK;YACH,CAAC,CAAC,IAAI,KAAK,uCAAuC;YAClD,CAAC,CAAC,iDAAiD,EACrD,8BAA8B,KAAK,0EAA0E,CAC9G,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,UAAU,CACd,4CAA4C,EAC5C,0DAA0D,CAC3D,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC/B,MAAM,UAAU,CACd,8DAA8D,EAC9D,6BAA6B,KAAK,iDAAiD,IAAI,IAAI,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { ReviewerReach, SourceReviewer } from '@ekanos/integration-schema';\n\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport { authRequiredError, usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport {\n type ReviewersApiResult,\n addReviewer,\n listReviewers,\n removeReviewer,\n} from '../reviewers-api';\nimport { resolveSourceTarget } from '../source-target';\n\nexport const REVIEWERS_SUBCOMMANDS = ['list', 'add', 'remove'] as const;\ntype ReviewersSubcommand = (typeof REVIEWERS_SUBCOMMANDS)[number];\n\nconst REACHES: readonly ReviewerReach[] = ['source', 'team'];\n\nexport interface ReviewersArgs {\n host?: string;\n source?: string;\n /** `list`, `add <email>`, `remove <email>`. */\n positionals: readonly string[];\n reach?: string;\n team?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `reviewers` — a Source admin names who decides its agents' reply drafts\n * held under an `approve` policy. A reviewer is one of the Source's own\n * users, at a reach: `source` (drafts from every team's provided agents) or\n * `team` (one named team's). `list` shows them; `add` names one; `remove`\n * takes one off — every reach, or only the named team's with `--team`.\n */\nexport async function runReviewers(\n ctx: CliContext,\n args: ReviewersArgs,\n): Promise<ExitCode> {\n const [rawSubcommand, rawEmail, ...extra] = args.positionals;\n const subcommand = parseSubcommand(rawSubcommand);\n\n if (subcommand === 'list') {\n if (rawEmail !== undefined || args.reach || args.team) {\n throw usageError(\n 'reviewers list takes no arguments.',\n 'Run \"ekanos reviewers list --source <slug>\".',\n );\n }\n } else if (extra.length > 0) {\n throw usageError(\n `Unexpected argument \"${extra[0]}\".`,\n 'See \"ekanos reviewers --help\".',\n );\n }\n\n const email = subcommand === 'list' ? '' : requireEmail(rawEmail, subcommand);\n const team = args.team === undefined ? undefined : requireTeam(args.team);\n const reach =\n subcommand === 'add' ? requireReach(args.reach, email, team) : undefined;\n if (subcommand === 'remove' && args.reach) {\n throw usageError(\n 'reviewers remove takes no --reach.',\n `Run \"ekanos reviewers remove ${email}\" (every reach) or add \"--team <slug>\" for one team's.`,\n );\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new ReviewersClient(env, resolved.session);\n const source = resolved.source;\n\n if (subcommand === 'list') {\n const list = await client.call((token) =>\n listReviewers(env.host, token, source),\n );\n if (list.reviewers.length === 0) {\n return ctx.succeed(\n { host: env.host, ...list },\n ctx.ui.result({\n title: `No reviewers on ${list.source.slug}`,\n tone: 'warn',\n notes: [\n 'Reply drafts under an \"approve\" policy wait for a named reviewer.',\n 'Name one: \"ekanos reviewers add <email> --reach source\".',\n ],\n }),\n );\n }\n return ctx.succeed(\n { host: env.host, ...list },\n [\n ctx.ui.bold(`Reviewers on ${list.source.slug}`),\n ctx.ui.table(\n ['Email', 'Name', 'Reach', 'Team'],\n list.reviewers.map(reviewerRow),\n ),\n ].join('\\n'),\n );\n }\n\n if (subcommand === 'add' && reach) {\n const result = await client.call((token) =>\n addReviewer(env.host, token, source, {\n email,\n reach,\n ...(team ? { team } : {}),\n }),\n );\n const reviewer = result.reviewer;\n return ctx.succeed(\n { host: env.host, ...result },\n ctx.ui.result({\n title: result.created\n ? `Added ${who(reviewer)} as a reviewer`\n : `${who(reviewer)} already reviews at that reach`,\n tone: result.created ? 'ok' : 'warn',\n rows: [\n ['Source', source],\n ['Reach', reachLabel(reviewer)],\n ],\n notes: [\n reviewer.reach === 'source'\n ? \"Decides drafts from every team's provided agents, in the Source's review queue.\"\n : `Decides ${reviewer.team?.slug ?? 'the team'}'s drafts, from its Approvals inbox or the Source's review queue.`,\n ],\n }),\n );\n }\n\n const result = await client.call((token) =>\n removeReviewer(env.host, token, source, {\n email,\n ...(team ? { team } : {}),\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n ctx.ui.result({\n title: `Removed ${email}${team ? ` from ${team}` : ''}`,\n rows: [\n ['Source', source],\n [\n 'Removed',\n `${result.removed} reach${result.removed === 1 ? '' : 'es'}`,\n ],\n ],\n }),\n );\n}\n\nfunction reviewerRow(reviewer: SourceReviewer): string[] {\n return [\n reviewer.email ?? reviewer.userId,\n reviewer.name ?? '—',\n reviewer.reach,\n reviewer.team?.slug ?? '—',\n ];\n}\n\nfunction reachLabel(reviewer: SourceReviewer): string {\n return reviewer.reach === 'team' && reviewer.team\n ? `team ${reviewer.team.slug} (${reviewer.team.name})`\n : 'source';\n}\n\nfunction who(reviewer: SourceReviewer): string {\n return reviewer.email ?? reviewer.name ?? reviewer.userId;\n}\n\nclass ReviewersClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<ReviewersApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the reviewers call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nfunction parseSubcommand(value: string | undefined): ReviewersSubcommand {\n const match = REVIEWERS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value\n ? `Unknown reviewers subcommand \"${value}\".`\n : 'reviewers needs a subcommand.',\n 'Run one of: ekanos reviewers list, ekanos reviewers add <email> --reach source|team [--team <slug>], ekanos reviewers remove <email> [--team <slug>].',\n );\n}\n\nfunction requireEmail(value: string | undefined, subcommand: 'add' | 'remove') {\n const email = value?.trim().toLowerCase();\n if (email && /^[^\\s@]+@[^\\s@]+$/.test(email)) return email;\n throw usageError(\n value\n ? `\"${value}\" is not an email address.`\n : 'Name the reviewer by email.',\n subcommand === 'add'\n ? 'e.g. \"ekanos reviewers add ana@example.com --reach source\".'\n : '\"ekanos reviewers list\" shows who reviews.',\n );\n}\n\nfunction requireTeam(value: string): string {\n const slug = value.trim().toLowerCase();\n if (/^[a-z0-9][a-z0-9-]*$/.test(slug)) return slug;\n throw usageError(\n `\"${value}\" is not a team slug.`,\n 'Run \"ekanos teams list\" to see the teams on this Source.',\n );\n}\n\nfunction requireReach(\n value: string | undefined,\n email: string,\n team: string | undefined,\n): ReviewerReach {\n const reach = REACHES.find((entry) => entry === value?.trim().toLowerCase());\n if (!reach) {\n throw usageError(\n value\n ? `\"${value}\" is not a reach: use source or team.`\n : 'Name the reach: --reach source or --reach team.',\n `e.g. \"ekanos reviewers add ${email} --reach source\", or \"--reach team --team <slug>\" for one team's drafts.`,\n );\n }\n if (reach === 'team' && !team) {\n throw usageError(\n 'A team-reach reviewer needs --team <slug>.',\n 'Run \"ekanos teams list\" to see the teams on this Source.',\n );\n }\n if (reach === 'source' && team) {\n throw usageError(\n 'A source-reach reviewer decides for every team; drop --team.',\n `Run \"ekanos reviewers add ${email} --reach source\", or use \"--reach team --team ${team}\".`,\n );\n }\n return reach;\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ export declare const RUNS_SUBCOMMANDS: readonly ['start', 'list', 'show'];
4
+ export declare const APPROVALS_SUBCOMMANDS: readonly ['list', 'approve', 'reject', 'edit'];
5
+ export interface RunsArgs {
6
+ host?: string;
7
+ source?: string;
8
+ positionals: readonly string[];
9
+ team?: string;
10
+ agent?: string;
11
+ prompt?: string;
12
+ input?: string;
13
+ follow: boolean;
14
+ reason?: string;
15
+ body?: string;
16
+ dir: string;
17
+ env: Record<string, string | undefined>;
18
+ /** Test seam for the `--follow` poll delay. */
19
+ sleep?: (ms: number) => Promise<void>;
20
+ }
21
+ /**
22
+ * `runs` — run, list and inspect a team's agents as its Source admin. A run
23
+ * started here is the app's "Run now": it runs as the agent's creator under
24
+ * the agent's own grant, policy and approvals (writes still wait for one),
25
+ * and is attributed to you.
26
+ */
27
+ export declare function runRuns(ctx: CliContext, args: RunsArgs): Promise<ExitCode>;
28
+ /**
29
+ * `agents test <key> --team <slug>`: run the template's latest version — its
30
+ * draft, published or not — on one team, without publishing it. Marked as a
31
+ * draft test run in the ledger; the team's stored agent still bounds every
32
+ * tool call, so a draft can narrow what runs but never widen it.
33
+ */
34
+ export declare function runAgentTest(ctx: CliContext, args: RunsArgs & {
35
+ key: string | undefined;
36
+ }): Promise<ExitCode>;
37
+ /**
38
+ * `approvals` — what a team's agent runs are waiting on, and deciding it.
39
+ * Decided with the authority a team's agent manager has in the app, and
40
+ * recorded as your decision.
41
+ */
42
+ export declare function runApprovals(ctx: CliContext, args: RunsArgs): Promise<ExitCode>;
@@ -0,0 +1,362 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { refreshStoredSession, requireSession, resolveAuthEnvironment, } from '../auth/session.js';
4
+ import { authRequiredError, usageError, validationError } from '../errors.js';
5
+ import { decideApproval, listApprovals, listRuns, showRun, startRun, } from '../runs-api.js';
6
+ import { resolveSourceTarget } from '../source-target.js';
7
+ export const RUNS_SUBCOMMANDS = ['start', 'list', 'show'];
8
+ export const APPROVALS_SUBCOMMANDS = [
9
+ 'list',
10
+ 'approve',
11
+ 'reject',
12
+ 'edit',
13
+ ];
14
+ const FOLLOW_INTERVAL_MS = 2000;
15
+ const FOLLOW_TIMEOUT_MS = 15 * 60 * 1000;
16
+ /**
17
+ * `runs` — run, list and inspect a team's agents as its Source admin. A run
18
+ * started here is the app's "Run now": it runs as the agent's creator under
19
+ * the agent's own grant, policy and approvals (writes still wait for one),
20
+ * and is attributed to you.
21
+ */
22
+ export async function runRuns(ctx, args) {
23
+ const [rawSubcommand, operand, ...extra] = args.positionals;
24
+ const subcommand = RUNS_SUBCOMMANDS.find((name) => name === rawSubcommand);
25
+ if (!subcommand) {
26
+ throw usageError(rawSubcommand
27
+ ? `Unknown runs subcommand "${rawSubcommand}".`
28
+ : 'runs needs a subcommand.', 'Run one of: ekanos runs start <agent> --team <slug> --prompt "…", ekanos runs list --team <slug>, ekanos runs show <run-id> --team <slug>.');
29
+ }
30
+ rejectExtra(extra, 'runs');
31
+ const team = requireTeam(args.team);
32
+ if (subcommand === 'start') {
33
+ const agent = requireOperand(operand, 'agent key', 'runs start');
34
+ return startAndReport(ctx, args, { team, agent, draft: false });
35
+ }
36
+ const { env, client, source } = await connect(ctx, args);
37
+ if (subcommand === 'list') {
38
+ if (operand)
39
+ rejectExtra([operand], 'runs list');
40
+ const list = await client.call((token) => listRuns(env.host, token, { source, team, agent: args.agent }));
41
+ return ctx.succeed(Object.assign({ host: env.host }, list), list.runs.length === 0
42
+ ? ctx.ui.result({
43
+ title: `No runs on ${list.team.slug}${args.agent ? ` for ${args.agent}` : ''}`,
44
+ tone: 'warn',
45
+ })
46
+ : ctx.ui.table(['RUN', 'AGENT', 'STATUS', 'TRIGGER', 'VERSION', 'STARTED'], list.runs.map((run) => [
47
+ run.id,
48
+ agentLabel(run.agent),
49
+ run.status,
50
+ run.trigger,
51
+ versionLabel(run),
52
+ run.startedAt.slice(0, 19).replace('T', ' '),
53
+ ])));
54
+ }
55
+ const runId = requireOperand(operand, 'run id', 'runs show');
56
+ const detail = await client.call((token) => showRun(env.host, token, { source, team, runId }));
57
+ return ctx.succeed(Object.assign({ host: env.host }, detail), runDetail(ctx.ui, detail));
58
+ }
59
+ /**
60
+ * `agents test <key> --team <slug>`: run the template's latest version — its
61
+ * draft, published or not — on one team, without publishing it. Marked as a
62
+ * draft test run in the ledger; the team's stored agent still bounds every
63
+ * tool call, so a draft can narrow what runs but never widen it.
64
+ */
65
+ export async function runAgentTest(ctx, args) {
66
+ const agent = requireOperand(args.key, 'agent key', 'agents test');
67
+ const team = requireTeam(args.team);
68
+ return startAndReport(ctx, args, { team, agent, draft: true });
69
+ }
70
+ /**
71
+ * `approvals` — what a team's agent runs are waiting on, and deciding it.
72
+ * Decided with the authority a team's agent manager has in the app, and
73
+ * recorded as your decision.
74
+ */
75
+ export async function runApprovals(ctx, args) {
76
+ const [rawSubcommand, operand, ...extra] = args.positionals;
77
+ const subcommand = APPROVALS_SUBCOMMANDS.find((name) => name === rawSubcommand);
78
+ if (!subcommand) {
79
+ throw usageError(rawSubcommand
80
+ ? `Unknown approvals subcommand "${rawSubcommand}".`
81
+ : 'approvals needs a subcommand.', 'Run one of: ekanos approvals list --team <slug>, ekanos approvals approve|reject <id> --team <slug> [--reason "…"], ekanos approvals edit <id> --team <slug> --body <file>.');
82
+ }
83
+ rejectExtra(extra, 'approvals');
84
+ const team = requireTeam(args.team);
85
+ if (subcommand === 'list') {
86
+ if (operand)
87
+ rejectExtra([operand], 'approvals list');
88
+ const { env, client, source } = await connect(ctx, args);
89
+ const list = await client.call((token) => listApprovals(env.host, token, { source, team }));
90
+ return ctx.succeed(Object.assign({ host: env.host }, list), list.approvals.length === 0
91
+ ? ctx.ui.result({ title: `Nothing waiting on ${list.team.slug}` })
92
+ : ctx.ui.result({
93
+ title: `${list.approvals.length} waiting on ${list.team.slug}`,
94
+ tone: 'warn',
95
+ rows: list.approvals.map((approval) => [
96
+ approval.id,
97
+ approvalLines(approval),
98
+ ]),
99
+ notes: [
100
+ '"ekanos approvals approve|reject <id> --team <slug>" decides one; "approvals edit <id> --body <file>" edits a reply draft and sends it.',
101
+ ],
102
+ }));
103
+ }
104
+ const approvalId = requireOperand(operand, 'approval id', `approvals ${subcommand}`);
105
+ const editedBody = subcommand === 'edit' ? readBodyFile(args.body, args.dir) : undefined;
106
+ if (subcommand !== 'edit' && args.body) {
107
+ throw usageError('--body is for "approvals edit".', `Run "ekanos approvals edit ${approvalId} --team ${team} --body <file>".`);
108
+ }
109
+ const { env, client, source } = await connect(ctx, args);
110
+ const decided = await client.call((token) => decideApproval(env.host, token, { source, team, approvalId }, Object.assign(Object.assign({ decision: subcommand === 'reject' ? 'rejected' : 'approved' }, (args.reason ? { reason: args.reason } : {})), (editedBody ? { body: editedBody } : {}))));
111
+ const approval = decided.approval;
112
+ return ctx.succeed(Object.assign({ host: env.host }, decided), ctx.ui.result({
113
+ title: `${approval.status === 'rejected' ? 'Rejected' : editedBody ? 'Edited and approved' : 'Approved'} ${approval.toolName}`,
114
+ tone: approval.status === 'rejected' ? 'warn' : 'ok',
115
+ rows: [
116
+ ['Agent', agentLabel(approval.agent)],
117
+ ['Run', approval.runId],
118
+ ],
119
+ notes: [
120
+ `The run picks it up now: "ekanos runs show ${approval.runId} --team ${team}".`,
121
+ ],
122
+ }));
123
+ }
124
+ async function startAndReport(ctx, args, target) {
125
+ const body = startBody(args, target);
126
+ const { env, client, source } = await connect(ctx, args);
127
+ const started = await client.call((token) => startRun(env.host, token, { source, team: target.team }, body));
128
+ const startedNote = `${target.draft ? 'Testing' : 'Started'} ${agentLabel(started.agent)} on ${started.team.slug}${started.draftTemplateVersion ? ` (draft v${started.draftTemplateVersion}, unpublished)` : ''}: run ${started.runId}`;
129
+ if (!args.follow) {
130
+ return ctx.succeed(Object.assign({ host: env.host }, started), ctx.ui.result({
131
+ title: startedNote,
132
+ notes: [
133
+ `Watch it: "ekanos runs show ${started.runId} --team ${target.team}".`,
134
+ ],
135
+ }));
136
+ }
137
+ ctx.log(startedNote);
138
+ const detail = await follow(ctx, args, async (after) => client.call((token) => showRun(env.host, token, {
139
+ source,
140
+ team: target.team,
141
+ runId: started.runId,
142
+ after,
143
+ })));
144
+ return ctx.succeed(Object.assign({ host: env.host, started }, detail), runDetail(ctx.ui, detail));
145
+ }
146
+ /**
147
+ * Poll the run, printing its status changes, its messages and each tool
148
+ * call as it lands, until it ends or parks on an approval.
149
+ */
150
+ async function follow(ctx, args, read) {
151
+ var _a;
152
+ const sleep = (_a = args.sleep) !== null && _a !== void 0 ? _a : ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
153
+ const seenCalls = new Set();
154
+ const events = [];
155
+ let lastEvent;
156
+ let lastStatus = '';
157
+ const deadline = Date.now() + FOLLOW_TIMEOUT_MS;
158
+ for (;;) {
159
+ const detail = await read(lastEvent);
160
+ for (const event of detail.events) {
161
+ events.push(event);
162
+ lastEvent = event.id;
163
+ for (const line of eventLines(event.message))
164
+ ctx.log(` ${line}`);
165
+ }
166
+ for (const call of detail.toolCalls) {
167
+ if (seenCalls.has(call.toolCallId))
168
+ continue;
169
+ seenCalls.add(call.toolCallId);
170
+ ctx.log(` ${call.ok === false ? '✗' : '✓'} ${call.toolName} (${call.effect}, ${call.authorizedVia})${call.error ? ` — ${call.error}` : ''}`);
171
+ }
172
+ if (detail.run.status !== lastStatus) {
173
+ lastStatus = detail.run.status;
174
+ ctx.log(` status: ${lastStatus}`);
175
+ }
176
+ const waiting = detail.approvals.some((approval) => approval.status === 'pending');
177
+ const ended = ['completed', 'failed', 'cancelled'].includes(detail.run.status);
178
+ if (ended || waiting || Date.now() > deadline) {
179
+ return Object.assign(Object.assign({}, detail), { events });
180
+ }
181
+ await sleep(FOLLOW_INTERVAL_MS);
182
+ }
183
+ }
184
+ /** Assistant text and tool calls from one live transcript message. */
185
+ function eventLines(message) {
186
+ if (!isRecord(message))
187
+ return [];
188
+ const content = message.content;
189
+ if (message.role === 'assistant' && typeof content === 'string') {
190
+ return content.trim() ? [`agent: ${clip(content)}`] : [];
191
+ }
192
+ if (!Array.isArray(content))
193
+ return [];
194
+ return content.flatMap((part) => {
195
+ if (!isRecord(part))
196
+ return [];
197
+ if (part.type === 'text' && message.role === 'assistant') {
198
+ return typeof part.text === 'string' && part.text.trim()
199
+ ? [`agent: ${clip(part.text)}`]
200
+ : [];
201
+ }
202
+ if (part.type === 'tool-call' && typeof part.toolName === 'string') {
203
+ return [`→ ${part.toolName}`];
204
+ }
205
+ return [];
206
+ });
207
+ }
208
+ function startBody(args, target) {
209
+ if (!args.prompt && !args.input) {
210
+ throw usageError('Give the run a prompt or an input.', `Pass --prompt "…" or --input <file.json>.`);
211
+ }
212
+ let input;
213
+ if (args.input) {
214
+ const file = path.resolve(args.dir, args.input);
215
+ let raw;
216
+ try {
217
+ raw = fs.readFileSync(file, 'utf8');
218
+ }
219
+ catch (_a) {
220
+ throw usageError(`Cannot read ${file}.`, 'Pass --input <file.json>.');
221
+ }
222
+ try {
223
+ input = JSON.parse(raw);
224
+ }
225
+ catch (_b) {
226
+ throw validationError(`${file} is not valid JSON.`, 'Fix the file, or pass the text with --prompt instead.');
227
+ }
228
+ }
229
+ return Object.assign(Object.assign(Object.assign({ agent: target.agent }, (args.prompt ? { prompt: args.prompt } : {})), (input !== undefined ? { input } : {})), { draft: target.draft });
230
+ }
231
+ function readBodyFile(file, dir) {
232
+ if (!file) {
233
+ throw usageError('approvals edit needs the reply to send.', 'Pass --body <file> with the edited reply text.');
234
+ }
235
+ const resolved = path.resolve(dir, file);
236
+ let text;
237
+ try {
238
+ text = fs.readFileSync(resolved, 'utf8');
239
+ }
240
+ catch (_a) {
241
+ throw usageError(`Cannot read ${resolved}.`, 'Pass --body <file>.');
242
+ }
243
+ if (!text.trim()) {
244
+ throw validationError(`${resolved} is empty.`, 'Write the reply to send.');
245
+ }
246
+ return text;
247
+ }
248
+ function runDetail(ui, detail) {
249
+ const { run } = detail;
250
+ const pending = detail.approvals.filter((approval) => approval.status === 'pending');
251
+ const rows = [
252
+ ['Agent', agentLabel(run.agent)],
253
+ ['Status', run.status],
254
+ ['Trigger', run.trigger],
255
+ ['Version', versionLabel(run)],
256
+ ['Started', run.startedAt],
257
+ ...(run.finishedAt ? [['Finished', run.finishedAt]] : []),
258
+ ...(run.error ? [['Error', run.error]] : []),
259
+ [
260
+ 'Tool calls',
261
+ detail.toolCalls.length === 0
262
+ ? 'none'
263
+ : detail.toolCalls.map((call) => `${call.ok === false ? '✗' : '✓'} ${call.toolName} (${call.effect}, ${call.authorizedVia})`),
264
+ ],
265
+ ...(pending.length > 0
266
+ ? [
267
+ [
268
+ 'Waiting on',
269
+ pending.flatMap((approval) => [
270
+ `${approval.id} ${approval.toolName}${approval.replyDraft ? ' (reply draft)' : ''}`,
271
+ ]),
272
+ ],
273
+ ]
274
+ : []),
275
+ ...(run.output ? [['Output', run.output.split('\n')]] : []),
276
+ ];
277
+ return ui.result({
278
+ title: `Run ${run.id}`,
279
+ tone: run.status === 'failed'
280
+ ? 'err'
281
+ : run.status === 'completed'
282
+ ? 'ok'
283
+ : 'warn',
284
+ rows,
285
+ notes: pending.length > 0
286
+ ? [
287
+ `Decide: "ekanos approvals approve|reject <id> --team ${detail.team.slug}". Full record: --json.`,
288
+ ]
289
+ : ['The full transcript and every tool call: --json.'],
290
+ });
291
+ }
292
+ function approvalLines(approval) {
293
+ var _a;
294
+ return [
295
+ `${approval.toolName} · ${agentLabel(approval.agent)}${approval.replyDraft ? ' · reply draft (editable)' : ''}`,
296
+ `run ${approval.runId}${approval.expiresAt ? ` · expires ${approval.expiresAt}` : ''}`,
297
+ clip(JSON.stringify((_a = approval.args) !== null && _a !== void 0 ? _a : null)),
298
+ ];
299
+ }
300
+ function agentLabel(agent) {
301
+ var _a;
302
+ return (_a = agent.templateKey) !== null && _a !== void 0 ? _a : agent.slug;
303
+ }
304
+ function versionLabel(run) {
305
+ return run.draftTemplateVersion
306
+ ? `v${run.agentVersion} · draft test of template v${run.draftTemplateVersion}`
307
+ : `v${run.agentVersion}`;
308
+ }
309
+ function clip(text, max = 200) {
310
+ const flat = text.replace(/\s+/g, ' ').trim();
311
+ return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
312
+ }
313
+ function isRecord(value) {
314
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
315
+ }
316
+ function requireTeam(value) {
317
+ const slug = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
318
+ if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug))
319
+ return slug;
320
+ throw usageError(value
321
+ ? `"${value}" is not a team slug.`
322
+ : 'Name the team with --team <slug>.', '"ekanos teams list" lists the teams on this Source.');
323
+ }
324
+ function requireOperand(value, what, command) {
325
+ const trimmed = value === null || value === void 0 ? void 0 : value.trim();
326
+ if (trimmed)
327
+ return trimmed;
328
+ throw usageError(`Name the ${what}.`, `See "ekanos ${command} --help".`);
329
+ }
330
+ function rejectExtra(extra, command) {
331
+ if (extra.length > 0) {
332
+ throw usageError(`Unexpected argument "${extra[0]}".`, `See "ekanos ${command.split(' ')[0]} --help".`);
333
+ }
334
+ }
335
+ async function connect(ctx, args) {
336
+ const env = resolveAuthEnvironment(ctx, args.host, args.env, {
337
+ projectDir: args.dir,
338
+ });
339
+ const resolved = await resolveSourceTarget(env, requireSession(env.store, env.host), args);
340
+ return {
341
+ env,
342
+ client: new RunsClient(env, resolved.session),
343
+ source: resolved.source,
344
+ };
345
+ }
346
+ class RunsClient {
347
+ constructor(env, session) {
348
+ this.env = env;
349
+ this.session = session;
350
+ }
351
+ async call(send) {
352
+ let result = await send(this.session.accessToken);
353
+ if (result.status === 'unauthorized') {
354
+ this.session = await refreshStoredSession(this.env, this.session);
355
+ result = await send(this.session.accessToken);
356
+ }
357
+ if (result.status === 'ok')
358
+ return result.data;
359
+ throw authRequiredError(`The session for ${this.env.host} could not authorize the call.`, `Run "ekanos login --host ${this.env.host}" and retry.`);
360
+ }
361
+ }
362
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AgentRunApproval,\n AgentRunDetail,\n AgentRunStartRequest,\n AgentRunSummary,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport { authRequiredError, usageError, validationError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport {\n type RunsApiResult,\n decideApproval,\n listApprovals,\n listRuns,\n showRun,\n startRun,\n} from '../runs-api';\nimport { resolveSourceTarget } from '../source-target';\nimport type { ResultRow, Ui } from '../ui';\n\nexport const RUNS_SUBCOMMANDS = ['start', 'list', 'show'] as const;\nexport const APPROVALS_SUBCOMMANDS = [\n 'list',\n 'approve',\n 'reject',\n 'edit',\n] as const;\n\nconst FOLLOW_INTERVAL_MS = 2000;\nconst FOLLOW_TIMEOUT_MS = 15 * 60 * 1000;\n\nexport interface RunsArgs {\n host?: string;\n source?: string;\n positionals: readonly string[];\n team?: string;\n agent?: string;\n prompt?: string;\n input?: string;\n follow: boolean;\n reason?: string;\n body?: string;\n dir: string;\n env: Record<string, string | undefined>;\n /** Test seam for the `--follow` poll delay. */\n sleep?: (ms: number) => Promise<void>;\n}\n\n/**\n * `runs` — run, list and inspect a team's agents as its Source admin. A run\n * started here is the app's \"Run now\": it runs as the agent's creator under\n * the agent's own grant, policy and approvals (writes still wait for one),\n * and is attributed to you.\n */\nexport async function runRuns(\n ctx: CliContext,\n args: RunsArgs,\n): Promise<ExitCode> {\n const [rawSubcommand, operand, ...extra] = args.positionals;\n const subcommand = RUNS_SUBCOMMANDS.find((name) => name === rawSubcommand);\n if (!subcommand) {\n throw usageError(\n rawSubcommand\n ? `Unknown runs subcommand \"${rawSubcommand}\".`\n : 'runs needs a subcommand.',\n 'Run one of: ekanos runs start <agent> --team <slug> --prompt \"…\", ekanos runs list --team <slug>, ekanos runs show <run-id> --team <slug>.',\n );\n }\n rejectExtra(extra, 'runs');\n const team = requireTeam(args.team);\n\n if (subcommand === 'start') {\n const agent = requireOperand(operand, 'agent key', 'runs start');\n return startAndReport(ctx, args, { team, agent, draft: false });\n }\n\n const { env, client, source } = await connect(ctx, args);\n\n if (subcommand === 'list') {\n if (operand) rejectExtra([operand], 'runs list');\n const list = await client.call((token) =>\n listRuns(env.host, token, { source, team, agent: args.agent }),\n );\n return ctx.succeed(\n { host: env.host, ...list },\n list.runs.length === 0\n ? ctx.ui.result({\n title: `No runs on ${list.team.slug}${args.agent ? ` for ${args.agent}` : ''}`,\n tone: 'warn',\n })\n : ctx.ui.table(\n ['RUN', 'AGENT', 'STATUS', 'TRIGGER', 'VERSION', 'STARTED'],\n list.runs.map((run) => [\n run.id,\n agentLabel(run.agent),\n run.status,\n run.trigger,\n versionLabel(run),\n run.startedAt.slice(0, 19).replace('T', ' '),\n ]),\n ),\n );\n }\n\n const runId = requireOperand(operand, 'run id', 'runs show');\n const detail = await client.call((token) =>\n showRun(env.host, token, { source, team, runId }),\n );\n return ctx.succeed({ host: env.host, ...detail }, runDetail(ctx.ui, detail));\n}\n\n/**\n * `agents test <key> --team <slug>`: run the template's latest version — its\n * draft, published or not — on one team, without publishing it. Marked as a\n * draft test run in the ledger; the team's stored agent still bounds every\n * tool call, so a draft can narrow what runs but never widen it.\n */\nexport async function runAgentTest(\n ctx: CliContext,\n args: RunsArgs & { key: string | undefined },\n): Promise<ExitCode> {\n const agent = requireOperand(args.key, 'agent key', 'agents test');\n const team = requireTeam(args.team);\n return startAndReport(ctx, args, { team, agent, draft: true });\n}\n\n/**\n * `approvals` — what a team's agent runs are waiting on, and deciding it.\n * Decided with the authority a team's agent manager has in the app, and\n * recorded as your decision.\n */\nexport async function runApprovals(\n ctx: CliContext,\n args: RunsArgs,\n): Promise<ExitCode> {\n const [rawSubcommand, operand, ...extra] = args.positionals;\n const subcommand = APPROVALS_SUBCOMMANDS.find(\n (name) => name === rawSubcommand,\n );\n if (!subcommand) {\n throw usageError(\n rawSubcommand\n ? `Unknown approvals subcommand \"${rawSubcommand}\".`\n : 'approvals needs a subcommand.',\n 'Run one of: ekanos approvals list --team <slug>, ekanos approvals approve|reject <id> --team <slug> [--reason \"…\"], ekanos approvals edit <id> --team <slug> --body <file>.',\n );\n }\n rejectExtra(extra, 'approvals');\n const team = requireTeam(args.team);\n\n if (subcommand === 'list') {\n if (operand) rejectExtra([operand], 'approvals list');\n const { env, client, source } = await connect(ctx, args);\n const list = await client.call((token) =>\n listApprovals(env.host, token, { source, team }),\n );\n return ctx.succeed(\n { host: env.host, ...list },\n list.approvals.length === 0\n ? ctx.ui.result({ title: `Nothing waiting on ${list.team.slug}` })\n : ctx.ui.result({\n title: `${list.approvals.length} waiting on ${list.team.slug}`,\n tone: 'warn',\n rows: list.approvals.map((approval): ResultRow => [\n approval.id,\n approvalLines(approval),\n ]),\n notes: [\n '\"ekanos approvals approve|reject <id> --team <slug>\" decides one; \"approvals edit <id> --body <file>\" edits a reply draft and sends it.',\n ],\n }),\n );\n }\n\n const approvalId = requireOperand(\n operand,\n 'approval id',\n `approvals ${subcommand}`,\n );\n const editedBody =\n subcommand === 'edit' ? readBodyFile(args.body, args.dir) : undefined;\n if (subcommand !== 'edit' && args.body) {\n throw usageError(\n '--body is for \"approvals edit\".',\n `Run \"ekanos approvals edit ${approvalId} --team ${team} --body <file>\".`,\n );\n }\n\n const { env, client, source } = await connect(ctx, args);\n const decided = await client.call((token) =>\n decideApproval(\n env.host,\n token,\n { source, team, approvalId },\n {\n decision: subcommand === 'reject' ? 'rejected' : 'approved',\n ...(args.reason ? { reason: args.reason } : {}),\n ...(editedBody ? { body: editedBody } : {}),\n },\n ),\n );\n const approval = decided.approval;\n return ctx.succeed(\n { host: env.host, ...decided },\n ctx.ui.result({\n title: `${approval.status === 'rejected' ? 'Rejected' : editedBody ? 'Edited and approved' : 'Approved'} ${approval.toolName}`,\n tone: approval.status === 'rejected' ? 'warn' : 'ok',\n rows: [\n ['Agent', agentLabel(approval.agent)],\n ['Run', approval.runId],\n ],\n notes: [\n `The run picks it up now: \"ekanos runs show ${approval.runId} --team ${team}\".`,\n ],\n }),\n );\n}\n\nasync function startAndReport(\n ctx: CliContext,\n args: RunsArgs,\n target: { team: string; agent: string; draft: boolean },\n): Promise<ExitCode> {\n const body = startBody(args, target);\n const { env, client, source } = await connect(ctx, args);\n const started = await client.call((token) =>\n startRun(env.host, token, { source, team: target.team }, body),\n );\n\n const startedNote = `${target.draft ? 'Testing' : 'Started'} ${agentLabel(started.agent)} on ${started.team.slug}${started.draftTemplateVersion ? ` (draft v${started.draftTemplateVersion}, unpublished)` : ''}: run ${started.runId}`;\n\n if (!args.follow) {\n return ctx.succeed(\n { host: env.host, ...started },\n ctx.ui.result({\n title: startedNote,\n notes: [\n `Watch it: \"ekanos runs show ${started.runId} --team ${target.team}\".`,\n ],\n }),\n );\n }\n\n ctx.log(startedNote);\n const detail = await follow(ctx, args, async (after) =>\n client.call((token) =>\n showRun(env.host, token, {\n source,\n team: target.team,\n runId: started.runId,\n after,\n }),\n ),\n );\n return ctx.succeed(\n { host: env.host, started, ...detail },\n runDetail(ctx.ui, detail),\n );\n}\n\n/**\n * Poll the run, printing its status changes, its messages and each tool\n * call as it lands, until it ends or parks on an approval.\n */\nasync function follow(\n ctx: CliContext,\n args: RunsArgs,\n read: (after: number | undefined) => Promise<AgentRunDetail>,\n): Promise<AgentRunDetail> {\n const sleep =\n args.sleep ??\n ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const seenCalls = new Set<string>();\n const events: AgentRunDetail['events'] = [];\n let lastEvent: number | undefined;\n let lastStatus = '';\n const deadline = Date.now() + FOLLOW_TIMEOUT_MS;\n\n for (;;) {\n const detail = await read(lastEvent);\n for (const event of detail.events) {\n events.push(event);\n lastEvent = event.id;\n for (const line of eventLines(event.message)) ctx.log(` ${line}`);\n }\n for (const call of detail.toolCalls) {\n if (seenCalls.has(call.toolCallId)) continue;\n seenCalls.add(call.toolCallId);\n ctx.log(\n ` ${call.ok === false ? '✗' : '✓'} ${call.toolName} (${call.effect}, ${call.authorizedVia})${call.error ? ` — ${call.error}` : ''}`,\n );\n }\n if (detail.run.status !== lastStatus) {\n lastStatus = detail.run.status;\n ctx.log(` status: ${lastStatus}`);\n }\n\n const waiting = detail.approvals.some(\n (approval) => approval.status === 'pending',\n );\n const ended = ['completed', 'failed', 'cancelled'].includes(\n detail.run.status,\n );\n if (ended || waiting || Date.now() > deadline) {\n return { ...detail, events };\n }\n await sleep(FOLLOW_INTERVAL_MS);\n }\n}\n\n/** Assistant text and tool calls from one live transcript message. */\nfunction eventLines(message: unknown): string[] {\n if (!isRecord(message)) return [];\n const content = message.content;\n if (message.role === 'assistant' && typeof content === 'string') {\n return content.trim() ? [`agent: ${clip(content)}`] : [];\n }\n if (!Array.isArray(content)) return [];\n return content.flatMap((part): string[] => {\n if (!isRecord(part)) return [];\n if (part.type === 'text' && message.role === 'assistant') {\n return typeof part.text === 'string' && part.text.trim()\n ? [`agent: ${clip(part.text)}`]\n : [];\n }\n if (part.type === 'tool-call' && typeof part.toolName === 'string') {\n return [`→ ${part.toolName}`];\n }\n return [];\n });\n}\n\nfunction startBody(\n args: RunsArgs,\n target: { agent: string; draft: boolean },\n): AgentRunStartRequest {\n if (!args.prompt && !args.input) {\n throw usageError(\n 'Give the run a prompt or an input.',\n `Pass --prompt \"…\" or --input <file.json>.`,\n );\n }\n let input: unknown;\n if (args.input) {\n const file = path.resolve(args.dir, args.input);\n let raw: string;\n try {\n raw = fs.readFileSync(file, 'utf8');\n } catch {\n throw usageError(`Cannot read ${file}.`, 'Pass --input <file.json>.');\n }\n try {\n input = JSON.parse(raw);\n } catch {\n throw validationError(\n `${file} is not valid JSON.`,\n 'Fix the file, or pass the text with --prompt instead.',\n );\n }\n }\n return {\n agent: target.agent,\n ...(args.prompt ? { prompt: args.prompt } : {}),\n ...(input !== undefined ? { input } : {}),\n draft: target.draft,\n };\n}\n\nfunction readBodyFile(file: string | undefined, dir: string): string {\n if (!file) {\n throw usageError(\n 'approvals edit needs the reply to send.',\n 'Pass --body <file> with the edited reply text.',\n );\n }\n const resolved = path.resolve(dir, file);\n let text: string;\n try {\n text = fs.readFileSync(resolved, 'utf8');\n } catch {\n throw usageError(`Cannot read ${resolved}.`, 'Pass --body <file>.');\n }\n if (!text.trim()) {\n throw validationError(`${resolved} is empty.`, 'Write the reply to send.');\n }\n return text;\n}\n\nfunction runDetail(ui: Ui, detail: AgentRunDetail): string {\n const { run } = detail;\n const pending = detail.approvals.filter(\n (approval) => approval.status === 'pending',\n );\n const rows: ResultRow[] = [\n ['Agent', agentLabel(run.agent)],\n ['Status', run.status],\n ['Trigger', run.trigger],\n ['Version', versionLabel(run)],\n ['Started', run.startedAt],\n ...(run.finishedAt ? [['Finished', run.finishedAt] as ResultRow] : []),\n ...(run.error ? [['Error', run.error] as ResultRow] : []),\n [\n 'Tool calls',\n detail.toolCalls.length === 0\n ? 'none'\n : detail.toolCalls.map(\n (call) =>\n `${call.ok === false ? '✗' : '✓'} ${call.toolName} (${call.effect}, ${call.authorizedVia})`,\n ),\n ],\n ...(pending.length > 0\n ? [\n [\n 'Waiting on',\n pending.flatMap((approval) => [\n `${approval.id} ${approval.toolName}${approval.replyDraft ? ' (reply draft)' : ''}`,\n ]),\n ] as ResultRow,\n ]\n : []),\n ...(run.output ? [['Output', run.output.split('\\n')] as ResultRow] : []),\n ];\n return ui.result({\n title: `Run ${run.id}`,\n tone:\n run.status === 'failed'\n ? 'err'\n : run.status === 'completed'\n ? 'ok'\n : 'warn',\n rows,\n notes:\n pending.length > 0\n ? [\n `Decide: \"ekanos approvals approve|reject <id> --team ${detail.team.slug}\". Full record: --json.`,\n ]\n : ['The full transcript and every tool call: --json.'],\n });\n}\n\nfunction approvalLines(approval: AgentRunApproval): string[] {\n return [\n `${approval.toolName} · ${agentLabel(approval.agent)}${approval.replyDraft ? ' · reply draft (editable)' : ''}`,\n `run ${approval.runId}${approval.expiresAt ? ` · expires ${approval.expiresAt}` : ''}`,\n clip(JSON.stringify(approval.args ?? null)),\n ];\n}\n\nfunction agentLabel(agent: AgentRunSummary['agent']): string {\n return agent.templateKey ?? agent.slug;\n}\n\nfunction versionLabel(run: AgentRunSummary): string {\n return run.draftTemplateVersion\n ? `v${run.agentVersion} · draft test of template v${run.draftTemplateVersion}`\n : `v${run.agentVersion}`;\n}\n\nfunction clip(text: string, max = 200): string {\n const flat = text.replace(/\\s+/g, ' ').trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requireTeam(value: string | undefined): string {\n const slug = value?.trim().toLowerCase();\n if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug)) return slug;\n throw usageError(\n value\n ? `\"${value}\" is not a team slug.`\n : 'Name the team with --team <slug>.',\n '\"ekanos teams list\" lists the teams on this Source.',\n );\n}\n\nfunction requireOperand(\n value: string | undefined,\n what: string,\n command: string,\n): string {\n const trimmed = value?.trim();\n if (trimmed) return trimmed;\n throw usageError(`Name the ${what}.`, `See \"ekanos ${command} --help\".`);\n}\n\nfunction rejectExtra(extra: readonly string[], command: string) {\n if (extra.length > 0) {\n throw usageError(\n `Unexpected argument \"${extra[0]}\".`,\n `See \"ekanos ${command.split(' ')[0]} --help\".`,\n );\n }\n}\n\nasync function connect(ctx: CliContext, args: RunsArgs) {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n return {\n env,\n client: new RunsClient(env, resolved.session),\n source: resolved.source,\n };\n}\n\nclass RunsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<RunsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import { type SourceSkillFile, type SourceSkillPushResult } from '@ekanos/integration-schema';
2
+ import type { StoredSession } from '../auth/credential-store.js';
3
+ import { type AuthEnvironment } from '../auth/session.js';
4
+ import type { CliContext } from '../context.js';
5
+ import type { ExitCode } from '../exit-codes.js';
6
+ import { type SkillsApiResult } from '../skills-api.js';
7
+ import { type Ui } from '../ui.js';
8
+ export declare const SKILLS_SUBCOMMANDS: readonly ['list', 'show', 'push', 'pull'];
9
+ /** Where an agent directory keeps the skills it uses: `agents/<key>/skills/<slug>/SKILL.md`. */
10
+ export declare const AGENT_SKILLS_DIR = "skills";
11
+ export interface SkillsArgs {
12
+ host?: string;
13
+ source?: string;
14
+ subcommand?: string;
15
+ /** A skill slug, or for `push` a skill folder. */
16
+ target?: string;
17
+ /** A team's slug: that team's own skills instead of the Source's. */
18
+ team?: string;
19
+ /** `pull`: where to write the folder (default `skills/<slug>`). */
20
+ out?: string;
21
+ dir: string;
22
+ env: Record<string, string | undefined>;
23
+ }
24
+ /**
25
+ * `skills` — the Source's skills, held by Ekanos in its skill store. A skill
26
+ * is a folder: `SKILL.md` plus any `references/` and `assets/`. `push`
27
+ * stores it as the skill's next version (created on first push, nothing
28
+ * stored when it is unchanged), live for every team at once — or with
29
+ * `--team`, as that one team's own skill. `pull` writes the folder back.
30
+ */
31
+ export declare function runSkills(ctx: CliContext, args: SkillsArgs): Promise<ExitCode>;
32
+ /** Every call refreshes the session once on a 401, then gives up. */
33
+ export declare class SkillsClient {
34
+ private readonly env;
35
+ private session;
36
+ constructor(env: AuthEnvironment, session: StoredSession);
37
+ call<T>(send: (accessToken: string) => Promise<SkillsApiResult<T>>): Promise<T>;
38
+ }
39
+ export declare function pushSkillFolder(client: SkillsClient, host: string, input: {
40
+ source: string;
41
+ team?: string;
42
+ folder: SkillFolder;
43
+ }): Promise<SourceSkillPushResult>;
44
+ export interface SkillFolder {
45
+ dir: string;
46
+ slug: string;
47
+ name: string;
48
+ description: string;
49
+ files: SourceSkillFile[];
50
+ }
51
+ /**
52
+ * Read a skill folder: `SKILL.md` and every other file under it. The slug is
53
+ * the frontmatter `name` when it is slug-shaped (Claude Code's own rule is
54
+ * that it matches the folder), else the folder's name; the description is
55
+ * the frontmatter's, else the first paragraph.
56
+ */
57
+ export declare function readSkillFolder(target: string, cwd: string): SkillFolder;
58
+ /** The skill folders beside an agent: `<agentDir>/skills/<slug>/SKILL.md`. */
59
+ export declare function findAgentSkillFolders(agentDir: string): string[];
60
+ export declare function pushSummary(ui: Ui, result: SourceSkillPushResult): string;