@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,188 @@
1
+ import { TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, } 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 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.
9
+ */
10
+ export async function runTeamAgentsArea(ctx, run) {
11
+ var _a;
12
+ const team = requireOperand(run.operands[0], 'team slug', 'agents');
13
+ const base = `/api/partner/teams/${encodeURIComponent(team)}/agents`;
14
+ if (run.verb === 'list') {
15
+ expectOperands(run, 1);
16
+ const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
17
+ method: 'GET',
18
+ path: base,
19
+ source: run.source,
20
+ }));
21
+ return ctx.succeed(Object.assign({ host: run.host }, list), [
22
+ ctx.ui.result({
23
+ title: list.agents.length === 0
24
+ ? `No agents are provided for ${list.team.slug}`
25
+ : `Agents for ${list.team.slug}`,
26
+ tone: list.agents.length === 0 ? 'warn' : 'ok',
27
+ }),
28
+ ...list.agents.map(describeEntry),
29
+ list.mcpServers.length > 0
30
+ ? `\nMCP servers: ${list.mcpServers.map((server) => `${server.key} (${server.status})`).join(', ')}`
31
+ : '',
32
+ ]
33
+ .filter(Boolean)
34
+ .join('\n'));
35
+ }
36
+ const key = requireOperand(run.operands[1], 'agent key', 'agents');
37
+ const path = `${base}/${encodeURIComponent(key)}`;
38
+ switch (run.verb) {
39
+ case 'enable': {
40
+ expectOperands(run, 2);
41
+ 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}`));
44
+ }
45
+ case 'disable': {
46
+ expectOperands(run, 2);
47
+ 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}`));
49
+ }
50
+ case 'pin': {
51
+ expectOperands(run, 3);
52
+ const version = Number(run.operands[2]);
53
+ if (!Number.isInteger(version) || version < 1) {
54
+ throw usageError(run.operands[2]
55
+ ? `"${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.`);
57
+ }
58
+ 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}`));
60
+ }
61
+ case 'unpin': {
62
+ expectOperands(run, 2);
63
+ 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}`));
65
+ }
66
+ case 'policy':
67
+ return policy(ctx, run, team, key, `${path}/policy`);
68
+ default:
69
+ throw usageError(`Unknown teams agents subcommand "${run.verb}".`, usageFor('agents'));
70
+ }
71
+ }
72
+ async function policy(ctx, run, team, key, path) {
73
+ const [action, tool, decision] = run.operands.slice(2);
74
+ const change = {};
75
+ const reads = approvalFlag(run, 'reads');
76
+ const writes = approvalFlag(run, 'writes');
77
+ if (reads)
78
+ change.reads = reads;
79
+ if (writes)
80
+ change.writes = writes;
81
+ if (action === 'set') {
82
+ const mode = parseApproval(decision);
83
+ if (!tool || !mode) {
84
+ throw usageError('policy set needs a tool and auto|approve.', `e.g. "ekanos teams agents policy ${team} ${key} set zendesk_reply_to_ticket approve".`);
85
+ }
86
+ change.set = { [tool]: mode };
87
+ }
88
+ else if (action === 'unset') {
89
+ if (!tool || decision) {
90
+ throw usageError('policy unset needs exactly one tool.', `e.g. "ekanos teams agents policy ${team} ${key} unset zendesk_reply_to_ticket".`);
91
+ }
92
+ change.unset = [tool];
93
+ }
94
+ else if (action !== undefined) {
95
+ throw usageError(`Unknown policy action "${action}".`, usageFor('agents'));
96
+ }
97
+ 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));
100
+ }
101
+ function describePolicy(ctx, policy, changed) {
102
+ const head = ctx.ui.result({
103
+ title: changed
104
+ ? `Policy updated for ${policy.slug} on ${policy.team.slug}`
105
+ : `Policy of ${policy.slug} on ${policy.team.slug}`,
106
+ tone: policy.editable ? 'ok' : 'warn',
107
+ rows: [
108
+ ['reads', policy.reads],
109
+ ['writes', policy.writes],
110
+ ['editable', policy.editable ? 'yes' : 'no — follows the template'],
111
+ ],
112
+ notes: policy.lockedReason ? [policy.lockedReason] : [],
113
+ });
114
+ if (policy.tools.length === 0) {
115
+ return `${head}\n\nNo tools yet: connect its integrations or MCP servers.`;
116
+ }
117
+ return `${head}\n\n${ctx.ui.table(['tool', 'from', 'effect', 'runs'], policy.tools.map((tool) => [
118
+ tool.name,
119
+ tool.source,
120
+ tool.effect,
121
+ `${tool.decision === 'auto' ? 'on its own' : 'waits for approval'}${tool.overridden ? ' (set per tool)' : ''}`,
122
+ ]))}`;
123
+ }
124
+ function change(run, path, method, body) {
125
+ return run.client.call((token) => call(run.host, token, TeamAgentChangeResultSchema, {
126
+ method,
127
+ path,
128
+ source: run.source,
129
+ body,
130
+ }));
131
+ }
132
+ function describeEntry(entry) {
133
+ var _a, _b, _c;
134
+ 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}`;
136
+ }
137
+ const agent = entry.agent;
138
+ const version = `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
139
+ const lines = [
140
+ `\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'}`,
142
+ ` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
143
+ ` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,
144
+ ];
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
+ }
148
+ return lines.join('\n');
149
+ }
150
+ function describeChange(result, title) {
151
+ var _a, _b, _c;
152
+ 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'}`,
155
+ ];
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.`);
158
+ }
159
+ if (result.missing.length > 0) {
160
+ lines.push(` Still to connect: ${result.missing.map((item) => `${item.name} (${item.key})`).join(', ')}`);
161
+ }
162
+ return lines.join('\n');
163
+ }
164
+ function expectOperands(run, count) {
165
+ const extra = run.operands[count];
166
+ if (extra !== undefined) {
167
+ throw usageError(`Unexpected argument "${extra}".`, usageFor('agents'));
168
+ }
169
+ }
170
+ function stringFlag(run, name) {
171
+ var _a;
172
+ const value = (_a = run.args.flags) === null || _a === void 0 ? void 0 : _a[name];
173
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
174
+ }
175
+ function parseApproval(value) {
176
+ return value === 'auto' || value === 'approve' ? value : null;
177
+ }
178
+ function approvalFlag(run, name) {
179
+ const value = stringFlag(run, name);
180
+ if (value === undefined)
181
+ return undefined;
182
+ const mode = parseApproval(value);
183
+ if (!mode) {
184
+ throw usageError(`--${name} takes auto or approve.`, usageFor('agents'));
185
+ }
186
+ return mode;
187
+ }
188
+ //# sourceMappingURL=team-agents-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-agents-agents.js","sourceRoot":"","sources":["../../src/commands/team-agents-agents.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type TeamAgentChangeResult,\n TeamAgentChangeResultSchema,\n type TeamAgentEntry,\n TeamAgentListSchema,\n type TeamAgentPolicy,\n type TeamAgentPolicyChange,\n TeamAgentPolicySchema,\n} from '@ekanos/integration-schema';\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 agents list|enable|disable|pin|unpin|policy` — a team's\n * provided agents, turned on, versioned and given an approval policy by the\n * Source admin.\n */\nexport async function runTeamAgentsArea(\n ctx: CliContext,\n run: TeamAgentRun,\n): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'agents');\n const base = `/api/partner/teams/${encodeURIComponent(team)}/agents`;\n\n if (run.verb === 'list') {\n expectOperands(run, 1);\n const list = await run.client.call((token) =>\n call(run.host, token, TeamAgentListSchema, {\n method: 'GET',\n path: base,\n source: run.source,\n }),\n );\n return ctx.succeed(\n { host: run.host, ...list },\n [\n ctx.ui.result({\n title:\n list.agents.length === 0\n ? `No agents are provided for ${list.team.slug}`\n : `Agents for ${list.team.slug}`,\n tone: list.agents.length === 0 ? 'warn' : 'ok',\n }),\n ...list.agents.map(describeEntry),\n list.mcpServers.length > 0\n ? `\\nMCP servers: ${list.mcpServers.map((server) => `${server.key} (${server.status})`).join(', ')}`\n : '',\n ]\n .filter(Boolean)\n .join('\\n'),\n );\n }\n\n const key = requireOperand(run.operands[1], 'agent key', 'agents');\n const path = `${base}/${encodeURIComponent(key)}`;\n\n switch (run.verb) {\n case 'enable': {\n expectOperands(run, 2);\n const as = stringFlag(run, 'as');\n const result = await change(run, `${path}/enable`, 'POST', {\n ...(as ? { as } : {}),\n });\n return ctx.succeed(\n { host: run.host, ...result },\n describeChange(\n result,\n `Turned on ${result.slug} for ${result.team.slug}`,\n ),\n );\n }\n case 'disable': {\n expectOperands(run, 2);\n const result = await change(run, `${path}/disable`, 'POST', {});\n return ctx.succeed(\n { host: run.host, ...result },\n describeChange(\n result,\n `Turned off ${result.slug} for ${result.team.slug}`,\n ),\n );\n }\n case 'pin': {\n expectOperands(run, 3);\n const version = Number(run.operands[2]);\n if (!Number.isInteger(version) || version < 1) {\n throw usageError(\n run.operands[2]\n ? `\"${run.operands[2]}\" is not a version number.`\n : 'Name the version to pin.',\n `e.g. \"ekanos teams agents pin ${team} ${key} 3\". \"ekanos agents show ${key}\" lists its versions.`,\n );\n }\n const result = await change(run, `${path}/pin`, 'PUT', { version });\n return ctx.succeed(\n { host: run.host, ...result },\n describeChange(\n result,\n `${result.team.slug} stays on v${result.version ?? version} of ${result.slug}`,\n ),\n );\n }\n case 'unpin': {\n expectOperands(run, 2);\n const result = await change(run, `${path}/pin`, 'PUT', { version: null });\n return ctx.succeed(\n { host: run.host, ...result },\n describeChange(\n result,\n `${result.team.slug} follows each published version of ${result.slug}`,\n ),\n );\n }\n case 'policy':\n return policy(ctx, run, team, key, `${path}/policy`);\n default:\n throw usageError(\n `Unknown teams agents subcommand \"${run.verb}\".`,\n usageFor('agents'),\n );\n }\n}\n\nasync function policy(\n ctx: CliContext,\n run: TeamAgentRun,\n team: string,\n key: string,\n path: string,\n): Promise<ExitCode> {\n const [action, tool, decision] = run.operands.slice(2);\n const change: TeamAgentPolicyChange = {};\n const reads = approvalFlag(run, 'reads');\n const writes = approvalFlag(run, 'writes');\n if (reads) change.reads = reads;\n if (writes) change.writes = writes;\n\n if (action === 'set') {\n const mode = parseApproval(decision);\n if (!tool || !mode) {\n throw usageError(\n 'policy set needs a tool and auto|approve.',\n `e.g. \"ekanos teams agents policy ${team} ${key} set zendesk_reply_to_ticket approve\".`,\n );\n }\n change.set = { [tool]: mode };\n } else if (action === 'unset') {\n if (!tool || decision) {\n throw usageError(\n 'policy unset needs exactly one tool.',\n `e.g. \"ekanos teams agents policy ${team} ${key} unset zendesk_reply_to_ticket\".`,\n );\n }\n change.unset = [tool];\n } else if (action !== undefined) {\n throw usageError(`Unknown policy action \"${action}\".`, usageFor('agents'));\n }\n\n const writing = Object.keys(change).length > 0;\n const result = await run.client.call((token) =>\n call(run.host, token, TeamAgentPolicySchema, {\n method: writing ? 'PUT' : 'GET',\n path,\n source: run.source,\n ...(writing ? { body: change } : {}),\n }),\n );\n return ctx.succeed(\n { host: run.host, ...result },\n describePolicy(ctx, result, writing),\n );\n}\n\nfunction describePolicy(\n ctx: CliContext,\n policy: TeamAgentPolicy,\n changed: boolean,\n): string {\n const head = ctx.ui.result({\n title: changed\n ? `Policy updated for ${policy.slug} on ${policy.team.slug}`\n : `Policy of ${policy.slug} on ${policy.team.slug}`,\n tone: policy.editable ? 'ok' : 'warn',\n rows: [\n ['reads', policy.reads],\n ['writes', policy.writes],\n ['editable', policy.editable ? 'yes' : 'no — follows the template'],\n ],\n notes: policy.lockedReason ? [policy.lockedReason] : [],\n });\n if (policy.tools.length === 0) {\n return `${head}\\n\\nNo tools yet: connect its integrations or MCP servers.`;\n }\n return `${head}\\n\\n${ctx.ui.table(\n ['tool', 'from', 'effect', 'runs'],\n policy.tools.map((tool) => [\n tool.name,\n tool.source,\n tool.effect,\n `${tool.decision === 'auto' ? 'on its own' : 'waits for approval'}${tool.overridden ? ' (set per tool)' : ''}`,\n ]),\n )}`;\n}\n\nfunction change(\n run: TeamAgentRun,\n path: string,\n method: 'POST' | 'PUT',\n body: unknown,\n): Promise<TeamAgentChangeResult> {\n return run.client.call((token) =>\n call(run.host, token, TeamAgentChangeResultSchema, {\n method,\n path,\n source: run.source,\n body,\n }),\n );\n}\n\nfunction describeEntry(entry: TeamAgentEntry): string {\n if (!entry.agent) {\n return `\\n${entry.key} — ${entry.name}\\n off · v${entry.publishedVersion ?? '?'} published · turn on: ekanos teams agents enable <team> ${entry.key}`;\n }\n const agent = entry.agent;\n const version = `v${agent.version ?? '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;\n const lines = [\n `\\n${entry.key} — ${entry.name}`,\n ` ${agent.status} · ${version} · runs as ${agent.runsAs ?? 'nobody'}${agent.accessConfirmed ? '' : ' · access not confirmed'}`,\n ` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,\n ` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,\n ];\n if (agent.missing.length > 0) {\n lines.push(\n ` missing: ${agent.missing.map((item) => `${item.name} (${item.kind === 'mcp' ? 'MCP server' : 'integration'} ${item.key})`).join(', ')}`,\n );\n }\n return lines.join('\\n');\n}\n\nfunction describeChange(result: TeamAgentChangeResult, title: string): string {\n const lines = [\n `✓ ${title}`,\n ` ${result.status} · v${result.version ?? '?'} ${result.pinned ? '(pinned)' : '(following)'} · runs as ${result.runsAs ?? 'nobody'}`,\n ];\n if (!result.accessConfirmed) {\n lines.push(\n ` ${result.runsAs ?? 'The person it runs as'} confirms it may use their connections on the agent's page in the app.`,\n );\n }\n if (result.missing.length > 0) {\n lines.push(\n ` Still to connect: ${result.missing.map((item) => `${item.name} (${item.key})`).join(', ')}`,\n );\n }\n return lines.join('\\n');\n}\n\nfunction expectOperands(run: TeamAgentRun, count: number) {\n const extra = run.operands[count];\n if (extra !== undefined) {\n throw usageError(`Unexpected argument \"${extra}\".`, usageFor('agents'));\n }\n}\n\nfunction stringFlag(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 parseApproval(value: string | undefined): 'auto' | 'approve' | null {\n return value === 'auto' || value === 'approve' ? value : null;\n}\n\nfunction approvalFlag(\n run: TeamAgentRun,\n name: 'reads' | 'writes',\n): 'auto' | 'approve' | undefined {\n const value = stringFlag(run, name);\n if (value === undefined) return undefined;\n const mode = parseApproval(value);\n if (!mode) {\n throw usageError(`--${name} takes auto or approve.`, usageFor('agents'));\n }\n return mode;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ import { type TeamAgentRun } from './team-agents.js';
4
+ export declare function runTeamMcp(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;
@@ -0,0 +1,218 @@
1
+ import { TeamMcpListSchema, TeamMcpStatusSchema, } from '@ekanos/integration-schema';
2
+ import { usageError } from '../errors.js';
3
+ import { call } from '../teams-api.js';
4
+ import { promptHidden } from './apps.js';
5
+ import { requireOperand, usageFor } from './team-agents.js';
6
+ /**
7
+ * `ekanos teams mcp list|add|status|token|effect` — a team's MCP servers,
8
+ * set up by its Source admin (`/api/partner/teams/<team>/mcp/*`).
9
+ *
10
+ * A bearer token is only ever typed at the admin's terminal with hidden
11
+ * input — never a flag, a file or a non-interactive run — so an agent
12
+ * driving the CLI never handles it. An OAuth server is signed in by a team
13
+ * member in their own browser: the CLI prints the link for them.
14
+ */
15
+ const AUTH_FLAGS = { none: 'none', token: 'bearer', oauth: 'oauth' };
16
+ export async function runTeamMcp(ctx, run) {
17
+ switch (run.verb) {
18
+ case 'list':
19
+ return list(ctx, run);
20
+ case 'add':
21
+ return add(ctx, run);
22
+ case 'status':
23
+ return status(ctx, run);
24
+ case 'token':
25
+ return token(ctx, run);
26
+ case 'effect':
27
+ return effect(ctx, run);
28
+ default:
29
+ throw usageError(`Unknown teams mcp subcommand "${run.verb}".`, usageFor('mcp'));
30
+ }
31
+ }
32
+ async function list(ctx, run) {
33
+ const team = requireOperand(run.operands[0], 'team slug', 'mcp');
34
+ noExtra(run, 1);
35
+ const data = await run.client.call((accessToken) => call(run.host, accessToken, TeamMcpListSchema, {
36
+ method: 'GET',
37
+ path: mcpPath(team),
38
+ source: run.source,
39
+ }));
40
+ return ctx.succeed(Object.assign({ host: run.host }, data), renderList(ctx, data));
41
+ }
42
+ async function add(ctx, run) {
43
+ var _a;
44
+ const team = requireOperand(run.operands[0], 'team slug', 'mcp');
45
+ const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');
46
+ noExtra(run, 2);
47
+ const url = stringFlag(run, 'url');
48
+ if (!url) {
49
+ throw usageError('teams mcp add needs the server URL.', `Run "ekanos teams mcp add ${team} ${key} --url https://… [--auth none|token|oauth]".`);
50
+ }
51
+ const authFlag = (_a = stringFlag(run, 'auth')) !== null && _a !== void 0 ? _a : 'oauth';
52
+ if (!(authFlag in AUTH_FLAGS)) {
53
+ throw usageError(`--auth must be none, token or oauth (got "${authFlag}").`, usageFor('mcp'));
54
+ }
55
+ const auth = AUTH_FLAGS[authFlag];
56
+ const added = await run.client.call((accessToken) => call(run.host, accessToken, TeamMcpStatusSchema, {
57
+ method: 'POST',
58
+ path: mcpPath(team),
59
+ source: run.source,
60
+ body: Object.assign({ key,
61
+ url,
62
+ auth }, (stringFlag(run, 'name') ? { name: stringFlag(run, 'name') } : {})),
63
+ }));
64
+ if (auth === 'bearer' && canPrompt(ctx, run)) {
65
+ return enterToken(ctx, run, team, key);
66
+ }
67
+ return ctx.succeed(Object.assign({ host: run.host }, added), renderStatus(ctx, added, `Added ${key} to ${team}`));
68
+ }
69
+ async function status(ctx, run) {
70
+ const team = requireOperand(run.operands[0], 'team slug', 'mcp');
71
+ const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');
72
+ noExtra(run, 2);
73
+ const data = await run.client.call((accessToken) => call(run.host, accessToken, TeamMcpStatusSchema, {
74
+ method: 'GET',
75
+ path: `${mcpPath(team)}/${encodeURIComponent(key)}`,
76
+ source: run.source,
77
+ }));
78
+ return ctx.succeed(Object.assign({ host: run.host }, data), renderStatus(ctx, data, `${key} on ${team}`));
79
+ }
80
+ async function token(ctx, run) {
81
+ const team = requireOperand(run.operands[0], 'team slug', 'mcp');
82
+ const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');
83
+ noExtra(run, 2);
84
+ if (!canPrompt(ctx, run)) {
85
+ throw usageError("teams mcp token takes the server's token at a terminal, never in a script or an agent run.", `Run it yourself in your terminal: npx @ekanos/cli teams mcp token ${team} ${key} --source ${run.source}`);
86
+ }
87
+ return enterToken(ctx, run, team, key);
88
+ }
89
+ async function enterToken(ctx, run, team, key) {
90
+ var _a;
91
+ const value = (await ((_a = run.args.askSecret) !== null && _a !== void 0 ? _a : promptHidden)(`Bearer token for ${key} on ${team} (hidden): `)).trim();
92
+ if (!value) {
93
+ throw usageError('No token entered; nothing was saved.', `Run "ekanos teams mcp token ${team} ${key}" when you have it.`);
94
+ }
95
+ const saved = await run.client.call((accessToken) => call(run.host, accessToken, TeamMcpStatusSchema, {
96
+ method: 'PUT',
97
+ path: `${mcpPath(team)}/${encodeURIComponent(key)}/token`,
98
+ source: run.source,
99
+ body: { token: value },
100
+ }));
101
+ return ctx.succeed(Object.assign({ host: run.host }, saved), renderStatus(ctx, saved, `Saved ${key}'s token for ${team}`));
102
+ }
103
+ async function effect(ctx, run) {
104
+ var _a, _b;
105
+ const team = requireOperand(run.operands[0], 'team slug', 'mcp');
106
+ const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');
107
+ const tool = (_a = run.operands[2]) === null || _a === void 0 ? void 0 : _a.trim();
108
+ const value = (_b = run.operands[3]) === null || _b === void 0 ? void 0 : _b.trim().toLowerCase();
109
+ noExtra(run, 4);
110
+ if (!tool || (value !== 'read' && value !== 'write')) {
111
+ throw usageError('teams mcp effect needs a tool and read or write.', `Run "ekanos teams mcp effect ${team} ${key} <tool> read|write"; "ekanos teams mcp status ${team} ${key}" lists the tools.`);
112
+ }
113
+ const saved = await run.client.call((accessToken) => call(run.host, accessToken, TeamMcpStatusSchema, {
114
+ method: 'PUT',
115
+ path: `${mcpPath(team)}/${encodeURIComponent(key)}/effects`,
116
+ source: run.source,
117
+ body: { tool, effect: value },
118
+ }));
119
+ return ctx.succeed(Object.assign({ host: run.host }, saved), renderStatus(ctx, saved, `${tool} on ${key} is now a ${value}`));
120
+ }
121
+ function renderList(ctx, data) {
122
+ if (data.servers.length === 0 && data.missing.length === 0) {
123
+ return ctx.ui.result({
124
+ title: `No MCP servers on ${data.team.slug}`,
125
+ tone: 'warn',
126
+ notes: [
127
+ `Add one: ekanos teams mcp add ${data.team.slug} <key> --url https://… --auth none|token|oauth`,
128
+ ],
129
+ });
130
+ }
131
+ return ctx.ui.result({
132
+ title: `MCP servers on ${data.team.slug}`,
133
+ tone: data.missing.some((entry) => entry.required) ||
134
+ data.servers.some((server) => server.status !== 'connected')
135
+ ? 'warn'
136
+ : 'ok',
137
+ rows: [
138
+ ...data.servers.map((server) => [
139
+ server.key,
140
+ describeServer(server),
141
+ ]),
142
+ ...data.missing.map((entry) => [
143
+ entry.key,
144
+ `✗ missing — ${entry.agent} ${entry.required ? 'needs' : 'can use'} ${entry.url}`,
145
+ ]),
146
+ ],
147
+ notes: [
148
+ `"ekanos teams mcp status ${data.team.slug} <key>" shows a server's tools and how to connect it.`,
149
+ ],
150
+ });
151
+ }
152
+ function renderStatus(ctx, data, title) {
153
+ const { server } = data;
154
+ const notes = [];
155
+ if (data.syncError)
156
+ notes.push(`Listing its tools failed: ${data.syncError}`);
157
+ if (data.connectUrl) {
158
+ notes.push('A team member who manages agents opens this link, signed in to the team, to connect it (you cannot sign in for them):', data.connectUrl);
159
+ }
160
+ else if (server.auth === 'bearer' && server.status !== 'connected') {
161
+ notes.push(`Enter its token in your terminal: npx @ekanos/cli teams mcp token ${data.team.slug} ${server.key}`);
162
+ }
163
+ if (data.effectsFromTemplate) {
164
+ notes.push("Its tools' effects come from the agent template (toolEffects in agent.json).");
165
+ }
166
+ else if (data.tools.some((tool) => !tool.confirmed)) {
167
+ notes.push(`Unconfirmed tools count as writes. Mark a read: ekanos teams mcp effect ${data.team.slug} ${server.key} <tool> read`);
168
+ }
169
+ return ctx.ui.result({
170
+ title,
171
+ tone: server.status === 'connected' && !data.syncError ? 'ok' : 'warn',
172
+ rows: [
173
+ ['Server', describeServer(server)],
174
+ ['URL', server.url],
175
+ ...(data.tools.length > 0
176
+ ? [
177
+ [
178
+ 'Tools',
179
+ data.tools.map((tool) => `${tool.name} · ${tool.effect}${tool.confirmed ? '' : ` (unconfirmed, server suggests ${tool.suggested})`}`),
180
+ ],
181
+ ]
182
+ : []),
183
+ ],
184
+ notes,
185
+ });
186
+ }
187
+ function describeServer(server) {
188
+ const state = server.status === 'connected'
189
+ ? `✓ connected · ${server.toolCount} tool${server.toolCount === 1 ? '' : 's'}`
190
+ : server.status === 'error'
191
+ ? `✗ error${server.lastError ? `: ${server.lastError}` : ''}`
192
+ : `✗ needs ${server.auth === 'oauth' ? 'sign-in' : server.auth === 'bearer' ? 'a token' : 'a refresh'}`;
193
+ const auth = server.auth === 'bearer' ? 'token' : server.auth;
194
+ const used = [
195
+ ...server.declaredBy.map((use) => `${use.agent} (${use.required ? 'required' : 'optional'}${use.urlMatches ? '' : ', different URL — not the one it needs'})`),
196
+ ...server.agents.filter((agent) => !server.declaredBy.some((use) => use.agent === agent)),
197
+ ];
198
+ return `${state} · ${auth}${used.length > 0 ? ` · used by ${used.join(', ')}` : ''}`;
199
+ }
200
+ function mcpPath(team) {
201
+ return `/api/partner/teams/${encodeURIComponent(team)}/mcp`;
202
+ }
203
+ function stringFlag(run, name) {
204
+ var _a;
205
+ const value = (_a = run.args.flags) === null || _a === void 0 ? void 0 : _a[name];
206
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
207
+ }
208
+ function noExtra(run, count) {
209
+ const extra = run.operands[count];
210
+ if (extra !== undefined) {
211
+ throw usageError(`Unexpected argument "${extra}".`, usageFor('mcp'));
212
+ }
213
+ }
214
+ function canPrompt(ctx, run) {
215
+ var _a;
216
+ return !ctx.jsonMode && ((_a = run.args.stdinIsTTY) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true);
217
+ }
218
+ //# sourceMappingURL=team-agents-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-agents-mcp.js","sourceRoot":"","sources":["../../src/commands/team-agents-mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type TeamMcpList,\n TeamMcpListSchema,\n type TeamMcpServer,\n type TeamMcpStatus,\n TeamMcpStatusSchema,\n} from '@ekanos/integration-schema';\n\nimport type { CliContext } from '../context';\nimport { usageError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { call } from '../teams-api';\nimport { promptHidden } from './apps';\nimport { type TeamAgentRun, requireOperand, usageFor } from './team-agents';\n\n/**\n * `ekanos teams mcp list|add|status|token|effect` — a team's MCP servers,\n * set up by its Source admin (`/api/partner/teams/<team>/mcp/*`).\n *\n * A bearer token is only ever typed at the admin's terminal with hidden\n * input — never a flag, a file or a non-interactive run — so an agent\n * driving the CLI never handles it. An OAuth server is signed in by a team\n * member in their own browser: the CLI prints the link for them.\n */\n\nconst AUTH_FLAGS = { none: 'none', token: 'bearer', oauth: 'oauth' } as const;\n\nexport async function runTeamMcp(\n ctx: CliContext,\n run: TeamAgentRun,\n): Promise<ExitCode> {\n switch (run.verb) {\n case 'list':\n return list(ctx, run);\n case 'add':\n return add(ctx, run);\n case 'status':\n return status(ctx, run);\n case 'token':\n return token(ctx, run);\n case 'effect':\n return effect(ctx, run);\n default:\n throw usageError(\n `Unknown teams mcp subcommand \"${run.verb}\".`,\n usageFor('mcp'),\n );\n }\n}\n\nasync function list(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'mcp');\n noExtra(run, 1);\n const data = await run.client.call((accessToken) =>\n call(run.host, accessToken, TeamMcpListSchema, {\n method: 'GET',\n path: mcpPath(team),\n source: run.source,\n }),\n );\n return ctx.succeed({ host: run.host, ...data }, renderList(ctx, data));\n}\n\nasync function add(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'mcp');\n const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');\n noExtra(run, 2);\n\n const url = stringFlag(run, 'url');\n if (!url) {\n throw usageError(\n 'teams mcp add needs the server URL.',\n `Run \"ekanos teams mcp add ${team} ${key} --url https://… [--auth none|token|oauth]\".`,\n );\n }\n const authFlag = stringFlag(run, 'auth') ?? 'oauth';\n if (!(authFlag in AUTH_FLAGS)) {\n throw usageError(\n `--auth must be none, token or oauth (got \"${authFlag}\").`,\n usageFor('mcp'),\n );\n }\n const auth = AUTH_FLAGS[authFlag as keyof typeof AUTH_FLAGS];\n\n const added = await run.client.call((accessToken) =>\n call(run.host, accessToken, TeamMcpStatusSchema, {\n method: 'POST',\n path: mcpPath(team),\n source: run.source,\n body: {\n key,\n url,\n auth,\n ...(stringFlag(run, 'name') ? { name: stringFlag(run, 'name') } : {}),\n },\n }),\n );\n\n if (auth === 'bearer' && canPrompt(ctx, run)) {\n return enterToken(ctx, run, team, key);\n }\n return ctx.succeed(\n { host: run.host, ...added },\n renderStatus(ctx, added, `Added ${key} to ${team}`),\n );\n}\n\nasync function status(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'mcp');\n const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');\n noExtra(run, 2);\n const data = await run.client.call((accessToken) =>\n call(run.host, accessToken, TeamMcpStatusSchema, {\n method: 'GET',\n path: `${mcpPath(team)}/${encodeURIComponent(key)}`,\n source: run.source,\n }),\n );\n return ctx.succeed(\n { host: run.host, ...data },\n renderStatus(ctx, data, `${key} on ${team}`),\n );\n}\n\nasync function token(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'mcp');\n const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');\n noExtra(run, 2);\n if (!canPrompt(ctx, run)) {\n throw usageError(\n \"teams mcp token takes the server's token at a terminal, never in a script or an agent run.\",\n `Run it yourself in your terminal: npx @ekanos/cli teams mcp token ${team} ${key} --source ${run.source}`,\n );\n }\n return enterToken(ctx, run, team, key);\n}\n\nasync function enterToken(\n ctx: CliContext,\n run: TeamAgentRun,\n team: string,\n key: string,\n): Promise<ExitCode> {\n const value = (\n await (run.args.askSecret ?? promptHidden)(\n `Bearer token for ${key} on ${team} (hidden): `,\n )\n ).trim();\n if (!value) {\n throw usageError(\n 'No token entered; nothing was saved.',\n `Run \"ekanos teams mcp token ${team} ${key}\" when you have it.`,\n );\n }\n const saved = await run.client.call((accessToken) =>\n call(run.host, accessToken, TeamMcpStatusSchema, {\n method: 'PUT',\n path: `${mcpPath(team)}/${encodeURIComponent(key)}/token`,\n source: run.source,\n body: { token: value },\n }),\n );\n return ctx.succeed(\n { host: run.host, ...saved },\n renderStatus(ctx, saved, `Saved ${key}'s token for ${team}`),\n );\n}\n\nasync function effect(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode> {\n const team = requireOperand(run.operands[0], 'team slug', 'mcp');\n const key = requireOperand(run.operands[1], 'MCP server key', 'mcp');\n const tool = run.operands[2]?.trim();\n const value = run.operands[3]?.trim().toLowerCase();\n noExtra(run, 4);\n if (!tool || (value !== 'read' && value !== 'write')) {\n throw usageError(\n 'teams mcp effect needs a tool and read or write.',\n `Run \"ekanos teams mcp effect ${team} ${key} <tool> read|write\"; \"ekanos teams mcp status ${team} ${key}\" lists the tools.`,\n );\n }\n const saved = await run.client.call((accessToken) =>\n call(run.host, accessToken, TeamMcpStatusSchema, {\n method: 'PUT',\n path: `${mcpPath(team)}/${encodeURIComponent(key)}/effects`,\n source: run.source,\n body: { tool, effect: value },\n }),\n );\n return ctx.succeed(\n { host: run.host, ...saved },\n renderStatus(ctx, saved, `${tool} on ${key} is now a ${value}`),\n );\n}\n\nfunction renderList(ctx: CliContext, data: TeamMcpList): string {\n if (data.servers.length === 0 && data.missing.length === 0) {\n return ctx.ui.result({\n title: `No MCP servers on ${data.team.slug}`,\n tone: 'warn',\n notes: [\n `Add one: ekanos teams mcp add ${data.team.slug} <key> --url https://… --auth none|token|oauth`,\n ],\n });\n }\n return ctx.ui.result({\n title: `MCP servers on ${data.team.slug}`,\n tone:\n data.missing.some((entry) => entry.required) ||\n data.servers.some((server) => server.status !== 'connected')\n ? 'warn'\n : 'ok',\n rows: [\n ...data.servers.map((server): [string, string] => [\n server.key,\n describeServer(server),\n ]),\n ...data.missing.map((entry): [string, string] => [\n entry.key,\n `✗ missing — ${entry.agent} ${entry.required ? 'needs' : 'can use'} ${entry.url}`,\n ]),\n ],\n notes: [\n `\"ekanos teams mcp status ${data.team.slug} <key>\" shows a server's tools and how to connect it.`,\n ],\n });\n}\n\nfunction renderStatus(\n ctx: CliContext,\n data: TeamMcpStatus,\n title: string,\n): string {\n const { server } = data;\n const notes: string[] = [];\n if (data.syncError) notes.push(`Listing its tools failed: ${data.syncError}`);\n if (data.connectUrl) {\n notes.push(\n 'A team member who manages agents opens this link, signed in to the team, to connect it (you cannot sign in for them):',\n data.connectUrl,\n );\n } else if (server.auth === 'bearer' && server.status !== 'connected') {\n notes.push(\n `Enter its token in your terminal: npx @ekanos/cli teams mcp token ${data.team.slug} ${server.key}`,\n );\n }\n if (data.effectsFromTemplate) {\n notes.push(\n \"Its tools' effects come from the agent template (toolEffects in agent.json).\",\n );\n } else if (data.tools.some((tool) => !tool.confirmed)) {\n notes.push(\n `Unconfirmed tools count as writes. Mark a read: ekanos teams mcp effect ${data.team.slug} ${server.key} <tool> read`,\n );\n }\n return ctx.ui.result({\n title,\n tone: server.status === 'connected' && !data.syncError ? 'ok' : 'warn',\n rows: [\n ['Server', describeServer(server)],\n ['URL', server.url],\n ...(data.tools.length > 0\n ? [\n [\n 'Tools',\n data.tools.map(\n (tool) =>\n `${tool.name} · ${tool.effect}${tool.confirmed ? '' : ` (unconfirmed, server suggests ${tool.suggested})`}`,\n ),\n ] as [string, string[]],\n ]\n : []),\n ],\n notes,\n });\n}\n\nfunction describeServer(server: TeamMcpServer): string {\n const state =\n server.status === 'connected'\n ? `✓ connected · ${server.toolCount} tool${server.toolCount === 1 ? '' : 's'}`\n : server.status === 'error'\n ? `✗ error${server.lastError ? `: ${server.lastError}` : ''}`\n : `✗ needs ${server.auth === 'oauth' ? 'sign-in' : server.auth === 'bearer' ? 'a token' : 'a refresh'}`;\n const auth = server.auth === 'bearer' ? 'token' : server.auth;\n const used = [\n ...server.declaredBy.map(\n (use) =>\n `${use.agent} (${use.required ? 'required' : 'optional'}${use.urlMatches ? '' : ', different URL — not the one it needs'})`,\n ),\n ...server.agents.filter(\n (agent) => !server.declaredBy.some((use) => use.agent === agent),\n ),\n ];\n return `${state} · ${auth}${used.length > 0 ? ` · used by ${used.join(', ')}` : ''}`;\n}\n\nfunction mcpPath(team: string): string {\n return `/api/partner/teams/${encodeURIComponent(team)}/mcp`;\n}\n\nfunction stringFlag(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(run: TeamAgentRun, count: number): void {\n const extra = run.operands[count];\n if (extra !== undefined) {\n throw usageError(`Unexpected argument \"${extra}\".`, usageFor('mcp'));\n }\n}\n\nfunction canPrompt(ctx: CliContext, run: TeamAgentRun): boolean {\n return !ctx.jsonMode && (run.args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ import { type TeamAgentRun } from './team-agents.js';
4
+ /**
5
+ * `ekanos teams triggers list|add|remove` and `ekanos teams links
6
+ * list|add|remove` — a team agent's triggers and outgoing links, set up by
7
+ * the Source admin. When the template keeps an area, the host shows the
8
+ * effective rows and refuses changes with the command that hands the area
9
+ * to the team.
10
+ */
11
+ export declare function runTeamTriggers(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;
12
+ export declare function runTeamLinks(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;