@ekanos/cli 0.10.0 → 0.12.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 (69) 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/apps.d.ts +6 -2
  9. package/dist/commands/apps.js +249 -4
  10. package/dist/commands/apps.js.map +1 -1
  11. package/dist/commands/reviewers.d.ts +21 -0
  12. package/dist/commands/reviewers.js +162 -0
  13. package/dist/commands/reviewers.js.map +1 -0
  14. package/dist/commands/routes.d.ts +23 -0
  15. package/dist/commands/routes.js +277 -0
  16. package/dist/commands/routes.js.map +1 -0
  17. package/dist/commands/runs.d.ts +42 -0
  18. package/dist/commands/runs.js +362 -0
  19. package/dist/commands/runs.js.map +1 -0
  20. package/dist/commands/skills.d.ts +60 -0
  21. package/dist/commands/skills.js +397 -0
  22. package/dist/commands/skills.js.map +1 -0
  23. package/dist/commands/team-agents-agents.d.ts +9 -0
  24. package/dist/commands/team-agents-agents.js +188 -0
  25. package/dist/commands/team-agents-agents.js.map +1 -0
  26. package/dist/commands/team-agents-mcp.d.ts +4 -0
  27. package/dist/commands/team-agents-mcp.js +218 -0
  28. package/dist/commands/team-agents-mcp.js.map +1 -0
  29. package/dist/commands/team-agents-triggers.d.ts +12 -0
  30. package/dist/commands/team-agents-triggers.js +251 -0
  31. package/dist/commands/team-agents-triggers.js.map +1 -0
  32. package/dist/commands/team-agents.d.ts +31 -0
  33. package/dist/commands/team-agents.js +71 -0
  34. package/dist/commands/team-agents.js.map +1 -0
  35. package/dist/commands/teams-onboard.d.ts +51 -0
  36. package/dist/commands/teams-onboard.js +261 -0
  37. package/dist/commands/teams-onboard.js.map +1 -0
  38. package/dist/commands/teams.d.ts +16 -1
  39. package/dist/commands/teams.js +22 -3
  40. package/dist/commands/teams.js.map +1 -1
  41. package/dist/connections-api.d.ts +125 -0
  42. package/dist/connections-api.js +156 -0
  43. package/dist/connections-api.js.map +1 -0
  44. package/dist/index.js +226 -6
  45. package/dist/index.js.map +1 -1
  46. package/dist/reviewers-api.d.ts +33 -0
  47. package/dist/reviewers-api.js +81 -0
  48. package/dist/reviewers-api.js.map +1 -0
  49. package/dist/routes-api.d.ts +105 -0
  50. package/dist/routes-api.js +147 -0
  51. package/dist/routes-api.js.map +1 -0
  52. package/dist/runs-api.d.ts +34 -0
  53. package/dist/runs-api.js +112 -0
  54. package/dist/runs-api.js.map +1 -0
  55. package/dist/skills-api.d.ts +28 -0
  56. package/dist/skills-api.js +104 -0
  57. package/dist/skills-api.js.map +1 -0
  58. package/dist/teams-api.d.ts +45 -3
  59. package/dist/teams-api.js +72 -3
  60. package/dist/teams-api.js.map +1 -1
  61. package/package.json +2 -2
  62. package/templates/package.json.tmpl +4 -4
  63. package/templates/skills/build-agent/SKILL.md +94 -10
  64. package/templates/skills/build-agent/references/agent-json.md +85 -4
  65. package/templates/skills/build-agent/references/rollout.md +9 -1
  66. package/templates/skills/build-agent/references/set-up-an-integration.md +59 -3
  67. package/templates/skills/build-agent/references/skills.md +81 -0
  68. package/templates/skills/build-agent/references/triggers.md +25 -5
  69. package/templates/skills/ekanos-platform/SKILL.md +116 -5
@@ -0,0 +1,251 @@
1
+ import { TeamAgentLinkAddResultSchema, TeamAgentLinkListSchema, TeamAgentRowRemoveResultSchema, TeamAgentTriggerAddResultSchema, TeamAgentTriggerListSchema, } from '@ekanos/integration-schema';
2
+ import { usageError } from '../errors.js';
3
+ import { call } from '../teams-api.js';
4
+ import { requireOperand, usageFor } from './team-agents.js';
5
+ /**
6
+ * `ekanos teams triggers list|add|remove` and `ekanos teams links
7
+ * list|add|remove` — a team agent's triggers and outgoing links, set up by
8
+ * the Source admin. When the template keeps an area, the host shows the
9
+ * effective rows and refuses changes with the command that hands the area
10
+ * to the team.
11
+ */
12
+ export async function runTeamTriggers(ctx, run) {
13
+ var _a;
14
+ const team = requireOperand(run.operands[0], 'team slug', 'triggers');
15
+ const key = requireOperand(run.operands[1], 'agent key', 'triggers');
16
+ const base = agentPath(team, key);
17
+ switch (run.verb) {
18
+ case 'list': {
19
+ noExtra(run.operands, 2, 'triggers');
20
+ const list = await send(run, TeamAgentTriggerListSchema, 'GET', `${base}/triggers`);
21
+ return ctx.succeed(Object.assign({ host: run.host }, list), ctx.ui.result({
22
+ title: list.triggers.length === 0
23
+ ? `${list.agent.slug} on ${list.team.slug} has no triggers`
24
+ : `Triggers of ${list.agent.slug} on ${list.team.slug}`,
25
+ tone: list.triggers.length === 0 ? 'warn' : 'ok',
26
+ rows: list.triggers.map((trigger) => [
27
+ trigger.id,
28
+ describeTrigger(trigger),
29
+ ]),
30
+ notes: list.teamOwned
31
+ ? [
32
+ '"ekanos teams triggers add <team> <key> manual|schedule|webhook|event …" adds one.',
33
+ ]
34
+ : [
35
+ `These follow the template. To let the team change them: ekanos agents overrides ${key} enable triggers`,
36
+ ],
37
+ }));
38
+ }
39
+ case 'add': {
40
+ const body = triggerBody(run, team, key);
41
+ const added = await send(run, TeamAgentTriggerAddResultSchema, 'POST', `${base}/triggers`, body);
42
+ const rows = [
43
+ ['Trigger', added.trigger.id],
44
+ ['Fires on', describeTrigger(added.trigger)],
45
+ ];
46
+ if (added.webhook) {
47
+ rows.push(['URL', added.webhook.url]);
48
+ rows.push(['Bearer token', added.webhook.token]);
49
+ }
50
+ return ctx.succeed(Object.assign({ host: run.host }, added), ctx.ui.result({
51
+ title: `Added a ${added.trigger.type} trigger to ${added.agent.slug} on ${added.team.slug}`,
52
+ tone: added.webhook ? 'warn' : 'ok',
53
+ rows,
54
+ notes: added.webhook
55
+ ? [
56
+ 'The URL and token are shown once and cannot be read again. POST JSON to the URL with "Authorization: Bearer <token>".',
57
+ ]
58
+ : [],
59
+ }));
60
+ }
61
+ case 'remove': {
62
+ const id = (_a = run.operands[2]) === null || _a === void 0 ? void 0 : _a.trim();
63
+ if (!id) {
64
+ throw usageError('Name the trigger to remove.', `List them: ekanos teams triggers list ${team} ${key}`);
65
+ }
66
+ noExtra(run.operands, 3, 'triggers');
67
+ const removed = await send(run, TeamAgentRowRemoveResultSchema, 'DELETE', `${base}/triggers/${encodeURIComponent(id)}`);
68
+ return ctx.succeed(Object.assign({ host: run.host }, removed), ctx.ui.result({
69
+ title: `Removed trigger ${removed.removed} from ${removed.agent.slug}`,
70
+ }));
71
+ }
72
+ default:
73
+ throw usageError(`Unknown teams triggers subcommand "${run.verb}".`, usageFor('triggers'));
74
+ }
75
+ }
76
+ export async function runTeamLinks(ctx, run) {
77
+ var _a;
78
+ const team = requireOperand(run.operands[0], 'team slug', 'links');
79
+ const from = requireOperand(run.operands[1], 'agent key', 'links');
80
+ const base = agentPath(team, from);
81
+ switch (run.verb) {
82
+ case 'list': {
83
+ noExtra(run.operands, 2, 'links');
84
+ const list = await send(run, TeamAgentLinkListSchema, 'GET', `${base}/links`);
85
+ return ctx.succeed(Object.assign({ host: run.host }, list), ctx.ui.result({
86
+ title: list.links.length === 0
87
+ ? `${list.agent.slug} on ${list.team.slug} has no links`
88
+ : `Links from ${list.agent.slug} on ${list.team.slug}`,
89
+ tone: list.links.length === 0 ? 'warn' : 'ok',
90
+ rows: list.links.map((link) => [link.id, describeLink(link)]),
91
+ notes: list.teamOwned
92
+ ? []
93
+ : [
94
+ `These follow the template. To let the team change them: ekanos agents overrides ${from} enable links`,
95
+ ],
96
+ }));
97
+ }
98
+ case 'add': {
99
+ const to = requireOperand(run.operands[2], 'agent key to link to', 'links');
100
+ noExtra(run.operands, 3, 'links');
101
+ const kind = flag(run, 'kind');
102
+ if (kind !== 'talk' && kind !== 'delegate') {
103
+ throw usageError('Say what kind of link: --kind talk|delegate.', usageFor('links'));
104
+ }
105
+ const mode = flag(run, 'mode');
106
+ if (mode !== undefined && mode !== 'await' && mode !== 'handoff') {
107
+ throw usageError('--mode is await or handoff.', usageFor('links'));
108
+ }
109
+ if (mode !== undefined && kind === 'talk') {
110
+ throw usageError('Only a delegate link takes --mode.', usageFor('links'));
111
+ }
112
+ const body = Object.assign({ to,
113
+ kind }, (mode ? { mode } : {}));
114
+ const added = await send(run, TeamAgentLinkAddResultSchema, 'POST', `${base}/links`, body);
115
+ return ctx.succeed(Object.assign({ host: run.host }, added), ctx.ui.result({
116
+ title: `Linked ${added.agent.slug} → ${added.link.to.slug} on ${added.team.slug}`,
117
+ rows: [
118
+ ['Link', added.link.id],
119
+ ['Kind', describeLink(added.link)],
120
+ ],
121
+ }));
122
+ }
123
+ case 'remove': {
124
+ const id = (_a = run.operands[2]) === null || _a === void 0 ? void 0 : _a.trim();
125
+ if (!id) {
126
+ throw usageError('Name the link to remove.', `List them: ekanos teams links list ${team} ${from}`);
127
+ }
128
+ noExtra(run.operands, 3, 'links');
129
+ const removed = await send(run, TeamAgentRowRemoveResultSchema, 'DELETE', `${base}/links/${encodeURIComponent(id)}`);
130
+ return ctx.succeed(Object.assign({ host: run.host }, removed), ctx.ui.result({
131
+ title: `Removed link ${removed.removed} from ${removed.agent.slug}`,
132
+ }));
133
+ }
134
+ default:
135
+ throw usageError(`Unknown teams links subcommand "${run.verb}".`, usageFor('links'));
136
+ }
137
+ }
138
+ function triggerBody(run, team, key) {
139
+ var _a, _b;
140
+ var _c, _d;
141
+ const type = (_a = run.operands[2]) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase();
142
+ const prompt = (_c = flag(run, 'prompt')) !== null && _c !== void 0 ? _c : '';
143
+ switch (type) {
144
+ case 'manual':
145
+ noExtra(run.operands, 3, 'triggers');
146
+ return { type: 'manual', promptTemplate: prompt };
147
+ case 'schedule': {
148
+ noExtra(run.operands, 3, 'triggers');
149
+ const cron = flag(run, 'cron');
150
+ if (!cron || !prompt) {
151
+ throw usageError('A schedule needs --cron and --prompt.', `e.g. ekanos teams triggers add ${team} ${key} schedule --cron "0 9 * * 1-5" --timezone America/Los_Angeles --prompt "Summarize yesterday's tickets"`);
152
+ }
153
+ return {
154
+ type: 'schedule',
155
+ scheduleCron: cron,
156
+ timezone: (_d = flag(run, 'timezone')) !== null && _d !== void 0 ? _d : 'UTC',
157
+ promptTemplate: prompt,
158
+ };
159
+ }
160
+ case 'webhook':
161
+ noExtra(run.operands, 3, 'triggers');
162
+ if (!prompt) {
163
+ throw usageError('A webhook needs --prompt: what to do with each request.', `e.g. ekanos teams triggers add ${team} ${key} webhook --prompt "Triage this alert: {{body.title}}"`);
164
+ }
165
+ return { type: 'webhook', promptTemplate: prompt };
166
+ case 'event':
167
+ case 'integration_event': {
168
+ const eventId = (_b = run.operands[3]) === null || _b === void 0 ? void 0 : _b.trim();
169
+ if (!eventId) {
170
+ throw usageError('Name the event, e.g. zendesk.ticket_created.', `e.g. ekanos teams triggers add ${team} ${key} event zendesk.ticket_created --filter '{"priority":["urgent"]}'`);
171
+ }
172
+ noExtra(run.operands, 4, 'triggers');
173
+ return {
174
+ type: 'integration_event',
175
+ eventId,
176
+ filter: parseFilter(flag(run, 'filter')),
177
+ promptTemplate: prompt,
178
+ };
179
+ }
180
+ case 'slack':
181
+ case 'linear':
182
+ throw usageError(`A ${type} trigger is connected in the app, where the team picks its workspace and channels.`, 'Open the agent in the app and add it under Triggers.');
183
+ default:
184
+ throw usageError(type ? `Unknown trigger type "${type}".` : 'Name the trigger type.', usageFor('triggers'));
185
+ }
186
+ }
187
+ function parseFilter(raw) {
188
+ if (!raw)
189
+ return {};
190
+ let parsed;
191
+ try {
192
+ parsed = JSON.parse(raw);
193
+ }
194
+ catch (_a) {
195
+ throw usageError('--filter must be a JSON object.', `e.g. --filter '{"priority":["urgent","high"]}'`);
196
+ }
197
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
198
+ throw usageError('--filter must be a JSON object.', `e.g. --filter '{"priority":["urgent","high"]}'`);
199
+ }
200
+ const filter = {};
201
+ for (const [name, value] of Object.entries(parsed)) {
202
+ if (typeof value === 'string' ||
203
+ typeof value === 'boolean' ||
204
+ (Array.isArray(value) && value.every((item) => typeof item === 'string'))) {
205
+ filter[name] = value;
206
+ continue;
207
+ }
208
+ throw usageError(`--filter field "${name}" must be a string, a boolean or a list of strings.`, `e.g. --filter '{"priority":["urgent","high"]}'`);
209
+ }
210
+ return filter;
211
+ }
212
+ function describeTrigger(trigger) {
213
+ var _a, _b, _c;
214
+ const what = trigger.type === 'schedule'
215
+ ? `schedule ${(_a = trigger.scheduleCron) !== null && _a !== void 0 ? _a : ''} (${(_b = trigger.timezone) !== null && _b !== void 0 ? _b : 'UTC'})`
216
+ : trigger.type === 'integration_event'
217
+ ? `event ${(_c = trigger.eventId) !== null && _c !== void 0 ? _c : ''}${trigger.filter && Object.keys(trigger.filter).length > 0 ? ` ${JSON.stringify(trigger.filter)}` : ''}`
218
+ : trigger.type;
219
+ const tags = [
220
+ trigger.owner === 'template' ? 'from template' : 'team',
221
+ trigger.active ? 'on' : 'off',
222
+ ];
223
+ return `${what} · ${tags.join(' · ')}`;
224
+ }
225
+ function describeLink(link) {
226
+ var _a;
227
+ const kind = link.kind === 'delegate' ? `delegate (${(_a = link.mode) !== null && _a !== void 0 ? _a : 'await'})` : 'talk';
228
+ const tags = [
229
+ link.owner === 'template' ? 'from template' : 'team',
230
+ ...(link.active ? [] : ['inactive']),
231
+ ];
232
+ return `${kind} → ${link.to.slug} · ${tags.join(' · ')}`;
233
+ }
234
+ function agentPath(team, key) {
235
+ return `/api/partner/teams/${encodeURIComponent(team)}/agents/${encodeURIComponent(key)}`;
236
+ }
237
+ function flag(run, name) {
238
+ var _a;
239
+ const value = (_a = run.args.flags) === null || _a === void 0 ? void 0 : _a[name];
240
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
241
+ }
242
+ function noExtra(operands, count, area) {
243
+ const extra = operands[count];
244
+ if (extra !== undefined) {
245
+ throw usageError(`Unexpected argument "${extra}".`, usageFor(area));
246
+ }
247
+ }
248
+ function send(run, schema, method, path, body) {
249
+ return run.client.call((token) => call(run.host, token, schema, { method, path, source: run.source, body }));
250
+ }
251
+ //# sourceMappingURL=team-agents-triggers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-agents-triggers.js","sourceRoot":"","sources":["../../src/commands/team-agents-triggers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type TeamAgentLink,\n type TeamAgentLinkAddRequest,\n TeamAgentLinkAddResultSchema,\n TeamAgentLinkListSchema,\n TeamAgentRowRemoveResultSchema,\n type TeamAgentTrigger,\n type TeamAgentTriggerAddRequest,\n TeamAgentTriggerAddResultSchema,\n TeamAgentTriggerListSchema,\n} from '@ekanos/integration-schema';\nimport type { z } from 'zod';\n\nimport type { CliContext } from '../context';\nimport { usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { call } from '../teams-api';\nimport { type TeamAgentRun, requireOperand, usageFor } from './team-agents';\n\n/**\n * `ekanos teams triggers list|add|remove` and `ekanos teams links\n * list|add|remove` — a team agent's triggers and outgoing links, set up by\n * the Source admin. When the template keeps an area, the host shows the\n * effective rows and refuses changes with the command that hands the area\n * to the team.\n */\n\nexport async function runTeamTriggers(\n ctx: CliContext,\n run: TeamAgentRun,\n): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'triggers');\n const key = requireOperand(run.operands[1], 'agent key', 'triggers');\n const base = agentPath(team, key);\n\n switch (run.verb) {\n case 'list': {\n noExtra(run.operands, 2, 'triggers');\n const list = await send(\n run,\n TeamAgentTriggerListSchema,\n 'GET',\n `${base}/triggers`,\n );\n return ctx.succeed(\n { host: run.host, ...list },\n ctx.ui.result({\n title:\n list.triggers.length === 0\n ? `${list.agent.slug} on ${list.team.slug} has no triggers`\n : `Triggers of ${list.agent.slug} on ${list.team.slug}`,\n tone: list.triggers.length === 0 ? 'warn' : 'ok',\n rows: list.triggers.map((trigger) => [\n trigger.id,\n describeTrigger(trigger),\n ]),\n notes: list.teamOwned\n ? [\n '\"ekanos teams triggers add <team> <key> manual|schedule|webhook|event …\" adds one.',\n ]\n : [\n `These follow the template. To let the team change them: ekanos agents overrides ${key} enable triggers`,\n ],\n }),\n );\n }\n case 'add': {\n const body = triggerBody(run, team, key);\n const added = await send(\n run,\n TeamAgentTriggerAddResultSchema,\n 'POST',\n `${base}/triggers`,\n body,\n );\n const rows: Array<[string, string]> = [\n ['Trigger', added.trigger.id],\n ['Fires on', describeTrigger(added.trigger)],\n ];\n if (added.webhook) {\n rows.push(['URL', added.webhook.url]);\n rows.push(['Bearer token', added.webhook.token]);\n }\n return ctx.succeed(\n { host: run.host, ...added },\n ctx.ui.result({\n title: `Added a ${added.trigger.type} trigger to ${added.agent.slug} on ${added.team.slug}`,\n tone: added.webhook ? 'warn' : 'ok',\n rows,\n notes: added.webhook\n ? [\n 'The URL and token are shown once and cannot be read again. POST JSON to the URL with \"Authorization: Bearer <token>\".',\n ]\n : [],\n }),\n );\n }\n case 'remove': {\n const id = run.operands[2]?.trim();\n if (!id) {\n throw usageError(\n 'Name the trigger to remove.',\n `List them: ekanos teams triggers list ${team} ${key}`,\n );\n }\n noExtra(run.operands, 3, 'triggers');\n const removed = await send(\n run,\n TeamAgentRowRemoveResultSchema,\n 'DELETE',\n `${base}/triggers/${encodeURIComponent(id)}`,\n );\n return ctx.succeed(\n { host: run.host, ...removed },\n ctx.ui.result({\n title: `Removed trigger ${removed.removed} from ${removed.agent.slug}`,\n }),\n );\n }\n default:\n throw usageError(\n `Unknown teams triggers subcommand \"${run.verb}\".`,\n usageFor('triggers'),\n );\n }\n}\n\nexport async function runTeamLinks(\n ctx: CliContext,\n run: TeamAgentRun,\n): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'links');\n const from = requireOperand(run.operands[1], 'agent key', 'links');\n const base = agentPath(team, from);\n\n switch (run.verb) {\n case 'list': {\n noExtra(run.operands, 2, 'links');\n const list = await send(\n run,\n TeamAgentLinkListSchema,\n 'GET',\n `${base}/links`,\n );\n return ctx.succeed(\n { host: run.host, ...list },\n ctx.ui.result({\n title:\n list.links.length === 0\n ? `${list.agent.slug} on ${list.team.slug} has no links`\n : `Links from ${list.agent.slug} on ${list.team.slug}`,\n tone: list.links.length === 0 ? 'warn' : 'ok',\n rows: list.links.map((link) => [link.id, describeLink(link)]),\n notes: list.teamOwned\n ? []\n : [\n `These follow the template. To let the team change them: ekanos agents overrides ${from} enable links`,\n ],\n }),\n );\n }\n case 'add': {\n const to = requireOperand(\n run.operands[2],\n 'agent key to link to',\n 'links',\n );\n noExtra(run.operands, 3, 'links');\n const kind = flag(run, 'kind');\n if (kind !== 'talk' && kind !== 'delegate') {\n throw usageError(\n 'Say what kind of link: --kind talk|delegate.',\n usageFor('links'),\n );\n }\n const mode = flag(run, 'mode');\n if (mode !== undefined && mode !== 'await' && mode !== 'handoff') {\n throw usageError('--mode is await or handoff.', usageFor('links'));\n }\n if (mode !== undefined && kind === 'talk') {\n throw usageError(\n 'Only a delegate link takes --mode.',\n usageFor('links'),\n );\n }\n const body: TeamAgentLinkAddRequest = {\n to,\n kind,\n ...(mode ? { mode } : {}),\n };\n const added = await send(\n run,\n TeamAgentLinkAddResultSchema,\n 'POST',\n `${base}/links`,\n body,\n );\n return ctx.succeed(\n { host: run.host, ...added },\n ctx.ui.result({\n title: `Linked ${added.agent.slug} → ${added.link.to.slug} on ${added.team.slug}`,\n rows: [\n ['Link', added.link.id],\n ['Kind', describeLink(added.link)],\n ],\n }),\n );\n }\n case 'remove': {\n const id = run.operands[2]?.trim();\n if (!id) {\n throw usageError(\n 'Name the link to remove.',\n `List them: ekanos teams links list ${team} ${from}`,\n );\n }\n noExtra(run.operands, 3, 'links');\n const removed = await send(\n run,\n TeamAgentRowRemoveResultSchema,\n 'DELETE',\n `${base}/links/${encodeURIComponent(id)}`,\n );\n return ctx.succeed(\n { host: run.host, ...removed },\n ctx.ui.result({\n title: `Removed link ${removed.removed} from ${removed.agent.slug}`,\n }),\n );\n }\n default:\n throw usageError(\n `Unknown teams links subcommand \"${run.verb}\".`,\n usageFor('links'),\n );\n }\n}\n\nfunction triggerBody(\n run: TeamAgentRun,\n team: string,\n key: string,\n): TeamAgentTriggerAddRequest {\n const type = run.operands[2]?.trim().toLowerCase();\n const prompt = flag(run, 'prompt') ?? '';\n switch (type) {\n case 'manual':\n noExtra(run.operands, 3, 'triggers');\n return { type: 'manual', promptTemplate: prompt };\n case 'schedule': {\n noExtra(run.operands, 3, 'triggers');\n const cron = flag(run, 'cron');\n if (!cron || !prompt) {\n throw usageError(\n 'A schedule needs --cron and --prompt.',\n `e.g. ekanos teams triggers add ${team} ${key} schedule --cron \"0 9 * * 1-5\" --timezone America/Los_Angeles --prompt \"Summarize yesterday's tickets\"`,\n );\n }\n return {\n type: 'schedule',\n scheduleCron: cron,\n timezone: flag(run, 'timezone') ?? 'UTC',\n promptTemplate: prompt,\n };\n }\n case 'webhook':\n noExtra(run.operands, 3, 'triggers');\n if (!prompt) {\n throw usageError(\n 'A webhook needs --prompt: what to do with each request.',\n `e.g. ekanos teams triggers add ${team} ${key} webhook --prompt \"Triage this alert: {{body.title}}\"`,\n );\n }\n return { type: 'webhook', promptTemplate: prompt };\n case 'event':\n case 'integration_event': {\n const eventId = run.operands[3]?.trim();\n if (!eventId) {\n throw usageError(\n 'Name the event, e.g. zendesk.ticket_created.',\n `e.g. ekanos teams triggers add ${team} ${key} event zendesk.ticket_created --filter '{\"priority\":[\"urgent\"]}'`,\n );\n }\n noExtra(run.operands, 4, 'triggers');\n return {\n type: 'integration_event',\n eventId,\n filter: parseFilter(flag(run, 'filter')),\n promptTemplate: prompt,\n };\n }\n case 'slack':\n case 'linear':\n throw usageError(\n `A ${type} trigger is connected in the app, where the team picks its workspace and channels.`,\n 'Open the agent in the app and add it under Triggers.',\n );\n default:\n throw usageError(\n type ? `Unknown trigger type \"${type}\".` : 'Name the trigger type.',\n usageFor('triggers'),\n );\n }\n}\n\nfunction parseFilter(\n raw: string | undefined,\n): Record<string, string | boolean | string[]> {\n if (!raw) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw usageError(\n '--filter must be a JSON object.',\n `e.g. --filter '{\"priority\":[\"urgent\",\"high\"]}'`,\n );\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw usageError(\n '--filter must be a JSON object.',\n `e.g. --filter '{\"priority\":[\"urgent\",\"high\"]}'`,\n );\n }\n const filter: Record<string, string | boolean | string[]> = {};\n for (const [name, value] of Object.entries(parsed)) {\n if (\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n (Array.isArray(value) && value.every((item) => typeof item === 'string'))\n ) {\n filter[name] = value as string | boolean | string[];\n continue;\n }\n throw usageError(\n `--filter field \"${name}\" must be a string, a boolean or a list of strings.`,\n `e.g. --filter '{\"priority\":[\"urgent\",\"high\"]}'`,\n );\n }\n return filter;\n}\n\nfunction describeTrigger(trigger: TeamAgentTrigger): string {\n const what =\n trigger.type === 'schedule'\n ? `schedule ${trigger.scheduleCron ?? ''} (${trigger.timezone ?? 'UTC'})`\n : trigger.type === 'integration_event'\n ? `event ${trigger.eventId ?? ''}${trigger.filter && Object.keys(trigger.filter).length > 0 ? ` ${JSON.stringify(trigger.filter)}` : ''}`\n : trigger.type;\n const tags = [\n trigger.owner === 'template' ? 'from template' : 'team',\n trigger.active ? 'on' : 'off',\n ];\n return `${what} · ${tags.join(' · ')}`;\n}\n\nfunction describeLink(link: TeamAgentLink): string {\n const kind =\n link.kind === 'delegate' ? `delegate (${link.mode ?? 'await'})` : 'talk';\n const tags = [\n link.owner === 'template' ? 'from template' : 'team',\n ...(link.active ? [] : ['inactive']),\n ];\n return `${kind} → ${link.to.slug} · ${tags.join(' · ')}`;\n}\n\nfunction agentPath(team: string, key: string): string {\n return `/api/partner/teams/${encodeURIComponent(team)}/agents/${encodeURIComponent(key)}`;\n}\n\nfunction flag(run: TeamAgentRun, name: string): string | undefined {\n const value = run.args.flags?.[name];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction noExtra(\n operands: readonly string[],\n count: number,\n area: 'triggers' | 'links',\n) {\n const extra = operands[count];\n if (extra !== undefined) {\n throw usageError(`Unexpected argument \"${extra}\".`, usageFor(area));\n }\n}\n\nfunction send<T>(\n run: TeamAgentRun,\n schema: z.ZodType<T>,\n method: 'GET' | 'POST' | 'DELETE',\n path: string,\n body?: unknown,\n): Promise<T> {\n return run.client.call((token) =>\n call(run.host, token, schema, { method, path, source: run.source, body }),\n );\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ import { TeamsClient, type TeamsArgs } from './teams.js';
4
+ /**
5
+ * `ekanos teams agents|triggers|links|mcp …` — a Source admin setting up a
6
+ * team's agents from the terminal, acting on that team through the partner
7
+ * API (`/api/partner/teams/<team>/agents/*`, `/mcp/*`). Every write goes
8
+ * through the same checks the app's agent pages make and leaves an Admin
9
+ * Audit row naming the person.
10
+ *
11
+ * The shape is always `teams <area> <verb> <team> [<agent-key> …]`.
12
+ */
13
+ export declare const TEAM_AGENT_AREAS: readonly ['agents', 'triggers', 'links', 'mcp'];
14
+ export type TeamAgentArea = (typeof TEAM_AGENT_AREAS)[number];
15
+ export declare function isTeamAgentArea(value: string | undefined): value is TeamAgentArea;
16
+ /** What every area handler gets: an authorized client and its operands. */
17
+ export interface TeamAgentRun {
18
+ args: TeamsArgs;
19
+ client: TeamsClient;
20
+ host: string;
21
+ /** The Source slug, for `?source=`. */
22
+ source: string;
23
+ /** The verb. */
24
+ verb: string;
25
+ /** Everything after the verb: `<team> [<key> …]`. */
26
+ operands: readonly string[];
27
+ }
28
+ export declare function runTeamAgentCommands(ctx: CliContext, args: TeamsArgs): Promise<ExitCode>;
29
+ export declare function usageFor(area: TeamAgentArea): string;
30
+ /** A slug operand (team, agent key, server key), or a usage error naming it. */
31
+ export declare function requireOperand(value: string | undefined, what: string, area: TeamAgentArea): string;
@@ -0,0 +1,71 @@
1
+ import { requireSession, resolveAuthEnvironment } from '../auth/session.js';
2
+ import { usageError } from '../errors.js';
3
+ import { resolveSourceTarget } from '../source-target.js';
4
+ import { runTeamAgentsArea } from './team-agents-agents.js';
5
+ import { runTeamMcp } from './team-agents-mcp.js';
6
+ import { runTeamLinks, runTeamTriggers } from './team-agents-triggers.js';
7
+ import { TeamsClient } from './teams.js';
8
+ /**
9
+ * `ekanos teams agents|triggers|links|mcp …` — a Source admin setting up a
10
+ * team's agents from the terminal, acting on that team through the partner
11
+ * API (`/api/partner/teams/<team>/agents/*`, `/mcp/*`). Every write goes
12
+ * through the same checks the app's agent pages make and leaves an Admin
13
+ * Audit row naming the person.
14
+ *
15
+ * The shape is always `teams <area> <verb> <team> [<agent-key> …]`.
16
+ */
17
+ export const TEAM_AGENT_AREAS = ['agents', 'triggers', 'links', 'mcp'];
18
+ export function isTeamAgentArea(value) {
19
+ return TEAM_AGENT_AREAS.some((area) => area === value);
20
+ }
21
+ export async function runTeamAgentCommands(ctx, args) {
22
+ const [area, verb, ...operands] = args.positionals;
23
+ if (!isTeamAgentArea(area)) {
24
+ throw usageError(`Unknown teams area "${area !== null && area !== void 0 ? area : ''}".`, 'See "ekanos teams --help".');
25
+ }
26
+ if (!verb) {
27
+ throw usageError(`teams ${area} needs a subcommand.`, usageFor(area));
28
+ }
29
+ const env = resolveAuthEnvironment(ctx, args.host, args.env, {
30
+ projectDir: args.dir,
31
+ });
32
+ const resolved = await resolveSourceTarget(env, requireSession(env.store, env.host), args);
33
+ const run = {
34
+ args,
35
+ client: new TeamsClient(env, resolved.session),
36
+ host: env.host,
37
+ source: resolved.source,
38
+ verb,
39
+ operands,
40
+ };
41
+ switch (area) {
42
+ case 'agents':
43
+ return runTeamAgentsArea(ctx, run);
44
+ case 'triggers':
45
+ return runTeamTriggers(ctx, run);
46
+ case 'links':
47
+ return runTeamLinks(ctx, run);
48
+ case 'mcp':
49
+ return runTeamMcp(ctx, run);
50
+ }
51
+ }
52
+ export function usageFor(area) {
53
+ switch (area) {
54
+ case 'agents':
55
+ return 'Run one of: ekanos teams agents list <team> | enable <team> <key> [--as <member-email>] | disable <team> <key> | pin <team> <key> <version> | unpin <team> <key> | policy <team> <key> [set <tool> auto|approve | unset <tool> | --reads auto|approve --writes auto|approve].';
56
+ case 'triggers':
57
+ return 'Run one of: ekanos teams triggers list <team> <key> | add <team> <key> <manual|schedule|webhook|event> … | remove <team> <key> <trigger-id>.';
58
+ case 'links':
59
+ return 'Run one of: ekanos teams links list <team> <key> | add <team> <from-key> <to-key> --kind talk|delegate [--mode await|handoff] | remove <team> <from-key> <link-id>.';
60
+ case 'mcp':
61
+ return 'Run one of: ekanos teams mcp list <team> | add <team> <server-key> --url <url> [--auth none|token|oauth] [--name <name>] | status <team> <server-key> | token <team> <server-key> (hidden input at your terminal) | effect <team> <server-key> <tool> read|write.';
62
+ }
63
+ }
64
+ /** A slug operand (team, agent key, server key), or a usage error naming it. */
65
+ export function requireOperand(value, what, area) {
66
+ const slug = value === null || value === void 0 ? void 0 : value.trim().toLowerCase();
67
+ if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug))
68
+ return slug;
69
+ throw usageError(value ? `"${value}" is not a ${what}.` : `Name the ${what}.`, usageFor(area));
70
+ }
71
+ //# sourceMappingURL=team-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-agents.js","sourceRoot":"","sources":["../../src/commands/team-agents.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireSession, resolveAuthEnvironment } from '../auth/session';\nimport type { CliContext } from '../context';\nimport { usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport { runTeamAgentsArea } from './team-agents-agents';\nimport { runTeamMcp } from './team-agents-mcp';\nimport { runTeamLinks, runTeamTriggers } from './team-agents-triggers';\nimport { TeamsClient, type TeamsArgs } from './teams';\n\n/**\n * `ekanos teams agents|triggers|links|mcp …` — a Source admin setting up a\n * team's agents from the terminal, acting on that team through the partner\n * API (`/api/partner/teams/<team>/agents/*`, `/mcp/*`). Every write goes\n * through the same checks the app's agent pages make and leaves an Admin\n * Audit row naming the person.\n *\n * The shape is always `teams <area> <verb> <team> [<agent-key> …]`.\n */\n\nexport const TEAM_AGENT_AREAS = ['agents', 'triggers', 'links', 'mcp'] as const;\nexport type TeamAgentArea = (typeof TEAM_AGENT_AREAS)[number];\n\nexport function isTeamAgentArea(\n value: string | undefined,\n): value is TeamAgentArea {\n return TEAM_AGENT_AREAS.some((area) => area === value);\n}\n\n/** What every area handler gets: an authorized client and its operands. */\nexport interface TeamAgentRun {\n args: TeamsArgs;\n client: TeamsClient;\n host: string;\n /** The Source slug, for `?source=`. */\n source: string;\n /** The verb. */\n verb: string;\n /** Everything after the verb: `<team> [<key> …]`. */\n operands: readonly string[];\n}\n\nexport async function runTeamAgentCommands(\n ctx: CliContext,\n args: TeamsArgs,\n): Promise<ExitCode> {\n const [area, verb, ...operands] = args.positionals;\n if (!isTeamAgentArea(area)) {\n throw usageError(\n `Unknown teams area \"${area ?? ''}\".`,\n 'See \"ekanos teams --help\".',\n );\n }\n if (!verb) {\n throw usageError(`teams ${area} needs a subcommand.`, usageFor(area));\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 run: TeamAgentRun = {\n args,\n client: new TeamsClient(env, resolved.session),\n host: env.host,\n source: resolved.source,\n verb,\n operands,\n };\n\n switch (area) {\n case 'agents':\n return runTeamAgentsArea(ctx, run);\n case 'triggers':\n return runTeamTriggers(ctx, run);\n case 'links':\n return runTeamLinks(ctx, run);\n case 'mcp':\n return runTeamMcp(ctx, run);\n }\n}\n\nexport function usageFor(area: TeamAgentArea): string {\n switch (area) {\n case 'agents':\n return 'Run one of: ekanos teams agents list <team> | enable <team> <key> [--as <member-email>] | disable <team> <key> | pin <team> <key> <version> | unpin <team> <key> | policy <team> <key> [set <tool> auto|approve | unset <tool> | --reads auto|approve --writes auto|approve].';\n case 'triggers':\n return 'Run one of: ekanos teams triggers list <team> <key> | add <team> <key> <manual|schedule|webhook|event> … | remove <team> <key> <trigger-id>.';\n case 'links':\n return 'Run one of: ekanos teams links list <team> <key> | add <team> <from-key> <to-key> --kind talk|delegate [--mode await|handoff] | remove <team> <from-key> <link-id>.';\n case 'mcp':\n return 'Run one of: ekanos teams mcp list <team> | add <team> <server-key> --url <url> [--auth none|token|oauth] [--name <name>] | status <team> <server-key> | token <team> <server-key> (hidden input at your terminal) | effect <team> <server-key> <tool> read|write.';\n }\n}\n\n/** A slug operand (team, agent key, server key), or a usage error naming it. */\nexport function requireOperand(\n value: string | undefined,\n what: string,\n area: TeamAgentArea,\n): 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 ? `\"${value}\" is not a ${what}.` : `Name the ${what}.`,\n usageFor(area),\n );\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ import type { TeamsClient } from './teams.js';
4
+ /**
5
+ * Onboarding a team from the terminal, for the Source admin: `teams create`,
6
+ * `teams members list|invite|role|remove`, `teams roles list` and
7
+ * `teams connect`. Parsed before any session is touched (`parseOnboarding`)
8
+ * so a usage error never costs a network round-trip, then run against the
9
+ * session `runTeams` resolved.
10
+ */
11
+ export declare const ONBOARDING_SUBCOMMANDS: readonly ['create', 'members', 'roles', 'connect'];
12
+ export type OnboardingSubcommand = (typeof ONBOARDING_SUBCOMMANDS)[number];
13
+ export interface OnboardingFlags {
14
+ slug?: string;
15
+ owner?: string;
16
+ role?: string;
17
+ yes: boolean;
18
+ }
19
+ export type OnboardingPlan = {
20
+ kind: 'create';
21
+ name: string;
22
+ slug?: string;
23
+ ownerEmail?: string;
24
+ } | {
25
+ kind: 'members-list';
26
+ team: string;
27
+ } | {
28
+ kind: 'members-invite';
29
+ team: string;
30
+ email: string;
31
+ role: string;
32
+ } | {
33
+ kind: 'members-role';
34
+ team: string;
35
+ email: string;
36
+ role: string;
37
+ } | {
38
+ kind: 'members-remove';
39
+ team: string;
40
+ email: string;
41
+ } | {
42
+ kind: 'roles-list';
43
+ team: string;
44
+ } | {
45
+ kind: 'connect';
46
+ team: string;
47
+ product: string;
48
+ };
49
+ export declare function isOnboardingSubcommand(value: string): value is OnboardingSubcommand;
50
+ export declare function parseOnboarding(subcommand: OnboardingSubcommand, rest: readonly string[], flags: OnboardingFlags): OnboardingPlan;
51
+ export declare function runOnboarding(ctx: CliContext, client: TeamsClient, host: string, source: string, plan: OnboardingPlan): Promise<ExitCode>;