@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,125 @@
1
+ import { z } from 'zod';
2
+ export declare const SourceConnectionSchema: z.ZodObject<{
3
+ slug: z.ZodString;
4
+ name: z.ZodString;
5
+ connected: z.ZodBoolean;
6
+ connectedBy: z.ZodNullable<z.ZodString>;
7
+ connectedAt: z.ZodNullable<z.ZodString>;
8
+ scope: z.ZodNullable<z.ZodString>;
9
+ app: z.ZodEnum<{
10
+ fields: "fields";
11
+ "source-app": "source-app";
12
+ }>;
13
+ fields: z.ZodArray<z.ZodObject<{
14
+ name: z.ZodString;
15
+ label: z.ZodString;
16
+ description: z.ZodNullable<z.ZodString>;
17
+ sensitive: z.ZodBoolean;
18
+ set: z.ZodBoolean;
19
+ value: z.ZodNullable<z.ZodString>;
20
+ }, z.core.$strip>>;
21
+ missing: z.ZodArray<z.ZodString>;
22
+ }, z.core.$strip>;
23
+ export type SourceConnection = z.infer<typeof SourceConnectionSchema>;
24
+ export type ConnectionsApiResult<T> = {
25
+ status: 'ok';
26
+ data: T;
27
+ } | {
28
+ status: 'unauthorized';
29
+ }
30
+ /** The integration supports no Source connection (409 NO_SOURCE_CONNECTION). */
31
+ | {
32
+ status: 'unsupported';
33
+ message: string;
34
+ }
35
+ /** App fields are still missing (409 NOT_CONFIGURED). */
36
+ | {
37
+ status: 'not-configured';
38
+ missing: string[];
39
+ connection: SourceConnection | null;
40
+ };
41
+ export declare function listConnections(host: string, token: string, source: string): Promise<ConnectionsApiResult<{
42
+ source: {
43
+ id: string;
44
+ slug: string;
45
+ name: string | null;
46
+ };
47
+ connections: {
48
+ slug: string;
49
+ name: string;
50
+ connected: boolean;
51
+ connectedBy: string | null;
52
+ connectedAt: string | null;
53
+ scope: string | null;
54
+ app: "fields" | "source-app";
55
+ fields: {
56
+ name: string;
57
+ label: string;
58
+ description: string | null;
59
+ sensitive: boolean;
60
+ set: boolean;
61
+ value: string | null;
62
+ }[];
63
+ missing: string[];
64
+ }[];
65
+ }>>;
66
+ export declare function showConnection(host: string, token: string, source: string, product: string): Promise<ConnectionsApiResult<{
67
+ source: {
68
+ id: string;
69
+ slug: string;
70
+ name: string | null;
71
+ };
72
+ connection: {
73
+ slug: string;
74
+ name: string;
75
+ connected: boolean;
76
+ connectedBy: string | null;
77
+ connectedAt: string | null;
78
+ scope: string | null;
79
+ app: "fields" | "source-app";
80
+ fields: {
81
+ name: string;
82
+ label: string;
83
+ description: string | null;
84
+ sensitive: boolean;
85
+ set: boolean;
86
+ value: string | null;
87
+ }[];
88
+ missing: string[];
89
+ };
90
+ callbackUrls: string[];
91
+ }>>;
92
+ export declare function startConnection(host: string, token: string, body: {
93
+ source: string;
94
+ product: string;
95
+ fields?: Record<string, string>;
96
+ }): Promise<ConnectionsApiResult<{
97
+ source: {
98
+ id: string;
99
+ slug: string;
100
+ name: string | null;
101
+ };
102
+ connection: {
103
+ slug: string;
104
+ name: string;
105
+ connected: boolean;
106
+ connectedBy: string | null;
107
+ connectedAt: string | null;
108
+ scope: string | null;
109
+ app: "fields" | "source-app";
110
+ fields: {
111
+ name: string;
112
+ label: string;
113
+ description: string | null;
114
+ sensitive: boolean;
115
+ set: boolean;
116
+ value: string | null;
117
+ }[];
118
+ missing: string[];
119
+ };
120
+ authorizeUrl: string;
121
+ callbackUrl: string;
122
+ }>>;
123
+ export declare function deleteConnection(host: string, token: string, source: string, product: string): Promise<ConnectionsApiResult<{
124
+ removed: boolean;
125
+ }>>;
@@ -0,0 +1,156 @@
1
+ import { z } from 'zod';
2
+ import { request } from './auth/ekanos-api.js';
3
+ import { authRequiredError, forbiddenError, invalidStateError, networkError, notFoundError, usageError, } from './errors.js';
4
+ /**
5
+ * The CLI's client for a Source's connections (plan 241): an integration a
6
+ * Source admin connects ONCE for the whole Source, used by the Source's
7
+ * provided agents in every team whose template marks it `owner: "source"`.
8
+ *
9
+ * GET /api/partner/connections?source=<slug|id>
10
+ * GET /api/partner/connections/<product>?source=<slug|id>
11
+ * POST /api/partner/connections/<product> { source, fields? } → authorizeUrl
12
+ * DELETE /api/partner/connections/<product>?source=<slug|id>
13
+ *
14
+ * The shapes are read here rather than from `@ekanos/integration-schema`, so
15
+ * this CLI works against a host without a schema release.
16
+ */
17
+ const SourceRefSchema = z.object({
18
+ id: z.string(),
19
+ slug: z.string(),
20
+ name: z.string().nullable(),
21
+ });
22
+ export const SourceConnectionSchema = z.object({
23
+ slug: z.string(),
24
+ name: z.string(),
25
+ connected: z.boolean(),
26
+ connectedBy: z.string().nullable(),
27
+ connectedAt: z.string().nullable(),
28
+ scope: z.string().nullable(),
29
+ app: z.enum(['source-app', 'fields']),
30
+ fields: z.array(z.object({
31
+ name: z.string(),
32
+ label: z.string(),
33
+ description: z.string().nullable(),
34
+ sensitive: z.boolean(),
35
+ set: z.boolean(),
36
+ value: z.string().nullable(),
37
+ })),
38
+ missing: z.array(z.string()),
39
+ });
40
+ const ListSchema = z.object({
41
+ source: SourceRefSchema,
42
+ connections: z.array(SourceConnectionSchema),
43
+ });
44
+ const ShowSchema = z.object({
45
+ source: SourceRefSchema,
46
+ connection: SourceConnectionSchema,
47
+ callbackUrls: z.array(z.string()),
48
+ });
49
+ const ConnectSchema = z.object({
50
+ source: SourceRefSchema,
51
+ connection: SourceConnectionSchema,
52
+ authorizeUrl: z.string(),
53
+ callbackUrl: z.string(),
54
+ });
55
+ const DisconnectSchema = z.object({ removed: z.boolean() });
56
+ export function listConnections(host, token, source) {
57
+ return call(host, token, ListSchema, null, {
58
+ method: 'GET',
59
+ path: `/api/partner/connections?${new URLSearchParams({ source })}`,
60
+ });
61
+ }
62
+ export function showConnection(host, token, source, product) {
63
+ return call(host, token, ShowSchema, product, {
64
+ method: 'GET',
65
+ path: `${route(product)}?${new URLSearchParams({ source })}`,
66
+ });
67
+ }
68
+ export function startConnection(host, token, body) {
69
+ return call(host, token, ConnectSchema, body.product, {
70
+ method: 'POST',
71
+ path: route(body.product),
72
+ body: Object.assign({ source: body.source }, (body.fields ? { fields: body.fields } : {})),
73
+ });
74
+ }
75
+ export function deleteConnection(host, token, source, product) {
76
+ return call(host, token, DisconnectSchema, product, {
77
+ method: 'DELETE',
78
+ path: `${route(product)}?${new URLSearchParams({ source })}`,
79
+ });
80
+ }
81
+ function route(product) {
82
+ return `/api/partner/connections/${encodeURIComponent(product)}`;
83
+ }
84
+ async function call(host, accessToken, schema, product, init) {
85
+ const response = await request(`${host}${init.path}`, {
86
+ method: init.method,
87
+ headers: Object.assign({ accept: 'application/json', authorization: `Bearer ${accessToken}` }, (init.body === undefined
88
+ ? {}
89
+ : { 'content-type': 'application/json' })),
90
+ body: init.body === undefined ? undefined : JSON.stringify(init.body),
91
+ });
92
+ if (response.status === 401 ||
93
+ (response.status >= 300 && response.status < 400)) {
94
+ return { status: 'unauthorized' };
95
+ }
96
+ const body = await readOptionalJson(response);
97
+ const code = typeof body.code === 'string' ? body.code : null;
98
+ const message = typeof body.error === 'string' && body.error ? body.error : null;
99
+ if (response.status === 403 && code === 'MFA_REQUIRED') {
100
+ throw authRequiredError(message !== null && message !== void 0 ? message : `${host} requires multi-factor authentication.`, 'Complete MFA in the browser, then run "ekanos login" again.');
101
+ }
102
+ if (response.status === 403) {
103
+ throw forbiddenError(message !== null && message !== void 0 ? message : 'Not permitted on this Source.', code === 'SOURCE_ADMIN_REQUIRED'
104
+ ? "Only a Source admin manages the Source's connections. Ask one to run it."
105
+ : 'Run "ekanos sources" to list the sources you hold a seat on.');
106
+ }
107
+ if (response.status === 404) {
108
+ throw notFoundError(message !== null && message !== void 0 ? message : `"${product !== null && product !== void 0 ? product : 'the Source'}" was not found.`, code === 'PRODUCT_NOT_ENTITLED'
109
+ ? '"ekanos catalog" lists what this Source has; Ekanos enables a product for a Source.'
110
+ : 'Run "ekanos sources" to list the sources you hold a seat on.');
111
+ }
112
+ if (response.status === 409 && code === 'NO_SOURCE_CONNECTION') {
113
+ return {
114
+ status: 'unsupported',
115
+ message: message !== null && message !== void 0 ? message : `"${product}" does not support one connection for the Source.`,
116
+ };
117
+ }
118
+ if (response.status === 409 && code === 'NOT_CONFIGURED') {
119
+ const parsed = SourceConnectionSchema.safeParse(body.connection);
120
+ return {
121
+ status: 'not-configured',
122
+ missing: Array.isArray(body.missing)
123
+ ? body.missing.filter((n) => typeof n === 'string')
124
+ : [],
125
+ connection: parsed.success ? parsed.data : null,
126
+ };
127
+ }
128
+ if (response.status === 400) {
129
+ throw usageError(message !== null && message !== void 0 ? message : 'The host refused the request.', 'See "ekanos apps --help".');
130
+ }
131
+ if (response.status === 409) {
132
+ throw invalidStateError(message !== null && message !== void 0 ? message : 'The host refused the request.', '');
133
+ }
134
+ if (!response.ok) {
135
+ throw networkError(`${host}${init.path.split('?')[0]} responded ${response.status}.`, response.status >= 500
136
+ ? 'The Ekanos deployment returned a server error. Retry shortly.'
137
+ : 'Confirm the host runs a build that includes the connections routes (plan 241).');
138
+ }
139
+ const parsed = schema.safeParse(body.data);
140
+ if (!parsed.success) {
141
+ throw networkError(`${host}/api/partner/connections answered in a shape this CLI does not read.`, 'Run "ekanos upgrade" — the CLI and the host disagree on the connections contract.');
142
+ }
143
+ return { status: 'ok', data: parsed.data };
144
+ }
145
+ async function readOptionalJson(response) {
146
+ try {
147
+ const parsed = await response.json();
148
+ return typeof parsed === 'object' && parsed !== null
149
+ ? parsed
150
+ : {};
151
+ }
152
+ catch (_a) {
153
+ return {};
154
+ }
155
+ }
156
+ //# sourceMappingURL=connections-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connections-api.js","sourceRoot":"","sources":["../src/connections-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\n\nimport { request } from './auth/ekanos-api';\nimport {\n authRequiredError,\n forbiddenError,\n invalidStateError,\n networkError,\n notFoundError,\n usageError,\n} from './errors';\n\n/**\n * The CLI's client for a Source's connections (plan 241): an integration a\n * Source admin connects ONCE for the whole Source, used by the Source's\n * provided agents in every team whose template marks it `owner: \"source\"`.\n *\n * GET /api/partner/connections?source=<slug|id>\n * GET /api/partner/connections/<product>?source=<slug|id>\n * POST /api/partner/connections/<product> { source, fields? } → authorizeUrl\n * DELETE /api/partner/connections/<product>?source=<slug|id>\n *\n * The shapes are read here rather than from `@ekanos/integration-schema`, so\n * this CLI works against a host without a schema release.\n */\n\nconst SourceRefSchema = z.object({\n id: z.string(),\n slug: z.string(),\n name: z.string().nullable(),\n});\n\nexport const SourceConnectionSchema = z.object({\n slug: z.string(),\n name: z.string(),\n connected: z.boolean(),\n connectedBy: z.string().nullable(),\n connectedAt: z.string().nullable(),\n scope: z.string().nullable(),\n app: z.enum(['source-app', 'fields']),\n fields: z.array(\n z.object({\n name: z.string(),\n label: z.string(),\n description: z.string().nullable(),\n sensitive: z.boolean(),\n set: z.boolean(),\n value: z.string().nullable(),\n }),\n ),\n missing: z.array(z.string()),\n});\nexport type SourceConnection = z.infer<typeof SourceConnectionSchema>;\n\nconst ListSchema = z.object({\n source: SourceRefSchema,\n connections: z.array(SourceConnectionSchema),\n});\nconst ShowSchema = z.object({\n source: SourceRefSchema,\n connection: SourceConnectionSchema,\n callbackUrls: z.array(z.string()),\n});\nconst ConnectSchema = z.object({\n source: SourceRefSchema,\n connection: SourceConnectionSchema,\n authorizeUrl: z.string(),\n callbackUrl: z.string(),\n});\nconst DisconnectSchema = z.object({ removed: z.boolean() });\n\nexport type ConnectionsApiResult<T> =\n | { status: 'ok'; data: T }\n | { status: 'unauthorized' }\n /** The integration supports no Source connection (409 NO_SOURCE_CONNECTION). */\n | { status: 'unsupported'; message: string }\n /** App fields are still missing (409 NOT_CONFIGURED). */\n | {\n status: 'not-configured';\n missing: string[];\n connection: SourceConnection | null;\n };\n\nexport function listConnections(host: string, token: string, source: string) {\n return call(host, token, ListSchema, null, {\n method: 'GET',\n path: `/api/partner/connections?${new URLSearchParams({ source })}`,\n });\n}\n\nexport function showConnection(\n host: string,\n token: string,\n source: string,\n product: string,\n) {\n return call(host, token, ShowSchema, product, {\n method: 'GET',\n path: `${route(product)}?${new URLSearchParams({ source })}`,\n });\n}\n\nexport function startConnection(\n host: string,\n token: string,\n body: { source: string; product: string; fields?: Record<string, string> },\n) {\n return call(host, token, ConnectSchema, body.product, {\n method: 'POST',\n path: route(body.product),\n body: {\n source: body.source,\n ...(body.fields ? { fields: body.fields } : {}),\n },\n });\n}\n\nexport function deleteConnection(\n host: string,\n token: string,\n source: string,\n product: string,\n) {\n return call(host, token, DisconnectSchema, product, {\n method: 'DELETE',\n path: `${route(product)}?${new URLSearchParams({ source })}`,\n });\n}\n\nfunction route(product: string): string {\n return `/api/partner/connections/${encodeURIComponent(product)}`;\n}\n\nasync function call<T>(\n host: string,\n accessToken: string,\n schema: z.ZodType<T>,\n product: string | null,\n init: { method: 'GET' | 'POST' | 'DELETE'; path: string; body?: unknown },\n): Promise<ConnectionsApiResult<T>> {\n const response = await request(`${host}${init.path}`, {\n method: init.method,\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n ...(init.body === undefined\n ? {}\n : { 'content-type': 'application/json' }),\n },\n body: init.body === undefined ? undefined : JSON.stringify(init.body),\n });\n\n if (\n response.status === 401 ||\n (response.status >= 300 && response.status < 400)\n ) {\n return { status: 'unauthorized' };\n }\n\n const body = await readOptionalJson(response);\n const code = typeof body.code === 'string' ? body.code : null;\n const message =\n typeof body.error === 'string' && body.error ? body.error : null;\n\n if (response.status === 403 && code === 'MFA_REQUIRED') {\n throw authRequiredError(\n message ?? `${host} requires multi-factor authentication.`,\n 'Complete MFA in the browser, then run \"ekanos login\" again.',\n );\n }\n if (response.status === 403) {\n throw forbiddenError(\n message ?? 'Not permitted on this Source.',\n code === 'SOURCE_ADMIN_REQUIRED'\n ? \"Only a Source admin manages the Source's connections. Ask one to run it.\"\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 404) {\n throw notFoundError(\n message ?? `\"${product ?? 'the Source'}\" was not found.`,\n code === 'PRODUCT_NOT_ENTITLED'\n ? '\"ekanos catalog\" lists what this Source has; Ekanos enables a product for a Source.'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 409 && code === 'NO_SOURCE_CONNECTION') {\n return {\n status: 'unsupported',\n message:\n message ??\n `\"${product}\" does not support one connection for the Source.`,\n };\n }\n if (response.status === 409 && code === 'NOT_CONFIGURED') {\n const parsed = SourceConnectionSchema.safeParse(body.connection);\n return {\n status: 'not-configured',\n missing: Array.isArray(body.missing)\n ? body.missing.filter((n): n is string => typeof n === 'string')\n : [],\n connection: parsed.success ? parsed.data : null,\n };\n }\n if (response.status === 400) {\n throw usageError(\n message ?? 'The host refused the request.',\n 'See \"ekanos apps --help\".',\n );\n }\n if (response.status === 409) {\n throw invalidStateError(message ?? 'The host refused the request.', '');\n }\n if (!response.ok) {\n throw networkError(\n `${host}${init.path.split('?')[0]} responded ${response.status}.`,\n response.status >= 500\n ? 'The Ekanos deployment returned a server error. Retry shortly.'\n : 'Confirm the host runs a build that includes the connections routes (plan 241).',\n );\n }\n\n const parsed = schema.safeParse(body.data);\n if (!parsed.success) {\n throw networkError(\n `${host}/api/partner/connections answered in a shape this CLI does not read.`,\n 'Run \"ekanos upgrade\" — the CLI and the host disagree on the connections contract.',\n );\n }\n return { status: 'ok', data: parsed.data };\n}\n\nasync function readOptionalJson(\n response: Response,\n): Promise<Record<string, unknown>> {\n try {\n const parsed: unknown = await response.json();\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -7,6 +7,10 @@ import { runInit } from './commands/init.js';
7
7
  import { runLogin } from './commands/login.js';
8
8
  import { runLogout } from './commands/logout.js';
9
9
  import { runPublish } from './commands/publish.js';
10
+ import { runReviewers } from './commands/reviewers.js';
11
+ import { runRoutes } from './commands/routes.js';
12
+ import { runApprovals, runRuns } from './commands/runs.js';
13
+ import { runSkills } from './commands/skills.js';
10
14
  import { runSources } from './commands/sources.js';
11
15
  import { runStatus } from './commands/status.js';
12
16
  import { runTeams } from './commands/teams.js';
@@ -87,13 +91,45 @@ const COMMAND_SPECS = {
87
91
  host: { type: 'string' },
88
92
  source: { type: 'string' },
89
93
  dir: { type: 'string' },
94
+ 'no-wait': { type: 'boolean' },
90
95
  },
91
96
  teams: {
92
97
  host: { type: 'string' },
93
98
  source: { type: 'string' },
94
99
  dir: { type: 'string' },
95
100
  connection: { type: 'string' },
101
+ slug: { type: 'string' },
102
+ owner: { type: 'string' },
103
+ role: { type: 'string' },
96
104
  yes: { type: 'boolean' },
105
+ // `teams agents|triggers|links|mcp` (team-agents.ts).
106
+ as: { type: 'string' },
107
+ reads: { type: 'string' },
108
+ writes: { type: 'string' },
109
+ effect: { type: 'string' },
110
+ kind: { type: 'string' },
111
+ mode: { type: 'string' },
112
+ url: { type: 'string' },
113
+ auth: { type: 'string' },
114
+ name: { type: 'string' },
115
+ cron: { type: 'string' },
116
+ timezone: { type: 'string' },
117
+ prompt: { type: 'string' },
118
+ filter: { type: 'string' },
119
+ },
120
+ reviewers: {
121
+ host: { type: 'string' },
122
+ source: { type: 'string' },
123
+ dir: { type: 'string' },
124
+ reach: { type: 'string' },
125
+ team: { type: 'string' },
126
+ },
127
+ routes: {
128
+ host: { type: 'string' },
129
+ source: { type: 'string' },
130
+ dir: { type: 'string' },
131
+ label: { type: 'string' },
132
+ webhook: { type: 'string' },
97
133
  },
98
134
  agents: {
99
135
  host: { type: 'string' },
@@ -107,6 +143,49 @@ const COMMAND_SPECS = {
107
143
  yes: { type: 'boolean' },
108
144
  force: { type: 'boolean' },
109
145
  claude: { type: 'boolean' },
146
+ // `agents test <key> --team <slug> --prompt|--input [--follow]`.
147
+ team: { type: 'string' },
148
+ prompt: { type: 'string' },
149
+ input: { type: 'string' },
150
+ follow: { type: 'boolean' },
151
+ // `apply`: `--no-skills` skips pushing the skill folders beside the agent.
152
+ skills: { type: 'boolean' },
153
+ // policy | triggers | links | overrides
154
+ event: { type: 'string' },
155
+ filter: { type: 'string', repeatable: true },
156
+ disabled: { type: 'boolean' },
157
+ cron: { type: 'string' },
158
+ timezone: { type: 'string' },
159
+ kind: { type: 'string' },
160
+ mode: { type: 'string' },
161
+ reads: { type: 'string' },
162
+ writes: { type: 'string' },
163
+ publish: { type: 'boolean' },
164
+ },
165
+ skills: {
166
+ host: { type: 'string' },
167
+ source: { type: 'string' },
168
+ dir: { type: 'string' },
169
+ team: { type: 'string' },
170
+ out: { type: 'string' },
171
+ },
172
+ runs: {
173
+ host: { type: 'string' },
174
+ source: { type: 'string' },
175
+ dir: { type: 'string' },
176
+ team: { type: 'string' },
177
+ agent: { type: 'string' },
178
+ prompt: { type: 'string' },
179
+ input: { type: 'string' },
180
+ follow: { type: 'boolean' },
181
+ },
182
+ approvals: {
183
+ host: { type: 'string' },
184
+ source: { type: 'string' },
185
+ dir: { type: 'string' },
186
+ team: { type: 'string' },
187
+ reason: { type: 'string' },
188
+ body: { type: 'string' },
110
189
  },
111
190
  use: {
112
191
  host: { type: 'string' },
@@ -133,9 +212,23 @@ const POSITIONAL_COMMANDS = {
133
212
  use: ['source-slug'],
134
213
  catalog: ['product-slug'],
135
214
  apps: ['subcommand', 'product-slug'],
136
- // `app set <team> <product>` is the longest form: four tokens.
137
- teams: ['subcommand', 'team-slug', 'product-slug', 'webhook-id'],
138
- agents: ['subcommand', 'key-or-path'],
215
+ // `teams agents policy <team> <key> set <tool> auto` is the longest form.
216
+ teams: [
217
+ 'subcommand',
218
+ 'team-slug',
219
+ 'product-slug',
220
+ 'webhook-id',
221
+ 'role',
222
+ 'arg-6',
223
+ 'arg-7',
224
+ ],
225
+ reviewers: ['subcommand', 'email'],
226
+ routes: ['subcommand', 'product-or-event-id', 'value', 'team-slug'],
227
+ skills: ['subcommand', 'slug-or-path'],
228
+ runs: ['subcommand', 'agent-key-or-run-id'],
229
+ approvals: ['subcommand', 'approval-id'],
230
+ // `triggers <key> add event <trigger-key>` is the longest form: five tokens.
231
+ agents: ['subcommand', 'key-or-path', 'action', 'arg', 'value'],
139
232
  };
140
233
  const COMMANDS = Object.keys(COMMAND_SPECS);
141
234
  const USAGE = [
@@ -163,18 +256,76 @@ const USAGE = [
163
256
  ' ("ekanos catalog [<product-slug>] --source <slug>", --json)',
164
257
  " apps The Source's app for an integration teams sign in through:",
165
258
  ' show <product> | set <product> (Source admin; takes the secret',
166
- ' at your terminal)',
167
- " teams A team's integration setup, for the Source admin:",
259
+ ' at your terminal) | connect <product> [--no-wait] (one',
260
+ " connection for the whole Source, used by the Source's provided",
261
+ ' agents in every team) | disconnect <product> | list',
262
+ " teams A Source's teams, for the Source admin:",
263
+ ' create <name> [--slug <slug>] [--owner <email>] (you own it',
264
+ ' unless --owner, who is invited as owner) |',
265
+ ' members list <team> | members invite <team> <email> [--role',
266
+ ' <role>] (default member; sends the invitation email) |',
267
+ ' members role <team> <email> <role> | members remove <team>',
268
+ " <email> --yes | roles list <team> (each role's permissions) |",
269
+ ' connect <team> <product> (the link a member opens to sign in',
270
+ ' an integration, and whether it is connected) |',
168
271
  ' list | show <team> <product> (a checklist: fields, callback',
169
272
  ' URLs, webhooks, connect link) | app set <team> <product>',
170
273
  ' [--connection <id>] (takes the secrets at your terminal) |',
171
274
  ' webhook <team> <product> [<webhook-id>] [--yes] (URL shown once)',
275
+ " A team's agents, for the Source admin (teams <area> <verb> <team> …):",
276
+ ' agents list <team> | agents enable <team> <key> [--as <member-email>]',
277
+ ' | agents disable|unpin <team> <key> | agents pin <team> <key> <version>',
278
+ ' | agents policy <team> <key> [set <tool> auto|approve | unset <tool>]',
279
+ ' [--reads auto|approve] [--writes auto|approve]',
280
+ ' triggers list|add|remove <team> <key> … | links list|add|remove',
281
+ ' <team> <from-key> [<to-key> --kind talk|delegate --mode await|handoff]',
282
+ ' | mcp list|add|status|token|effect <team> [<server-key> …]',
283
+ ' (see "ekanos teams --help")',
284
+ ' reviewers Who decides agent reply drafts, for the Source admin:',
285
+ ' list | add <email> --reach source|team [--team <slug>] |',
286
+ ' remove <email> [--team <slug>]',
287
+ " routes Route a Source connection's events to teams, for the Source admin:",
288
+ ' list [<product>] | options <product> | set <product> <value> <team>',
289
+ ' [--label <name>] | remove <product> <value> | webhook <product>',
290
+ ' [--webhook <id>] (URL shown once) | unrouted [<product>] |',
291
+ ' replay <event-id>',
172
292
  " agents The source's agent templates, held by Ekanos:",
173
293
  ' init [<dir>] [--claude|--no-claude] (skills + docs MCP for designing',
174
294
  ' agents with Claude; offers to add the docs to Claude Code)',
175
295
  ' list | show <key> | pull <key> [--out <dir>]',
176
296
  ' apply <dir|file> [--base-version <n>] [--overwrite]',
177
297
  ' publish <key> [--to <n>] --yes | rollback <key> --to <n> --yes',
298
+ ' test <key> --team <slug> (--prompt "…" | --input <file.json>)',
299
+ ' [--follow] (runs the latest, unpublished version on one team;',
300
+ ' same grant, policy, approvals and audit; marked as a test)',
301
+ ' apply also pushes <dir>/skills/<slug>/ folders first and names',
302
+ ' them in the agent (--no-skills skips that)',
303
+ ' Edit one template in place (stores a draft version; --publish',
304
+ ' also rolls it out, with --yes):',
305
+ ' policy <key> [set <tool> auto|approve | unset <tool>]',
306
+ ' [--reads auto|approve] [--writes auto|approve]',
307
+ ' triggers <key> [list | add event <k> --event <slug.event>',
308
+ ' [--filter field=a,b]... | add schedule <k> --cron "<expr>"',
309
+ ' [--timezone <tz>] --prompt <text> | add webhook <k> --prompt',
310
+ ' <text> | remove <k>] [--prompt <text>] [--disabled]',
311
+ ' links <key> [list | add <to-key> --kind talk|delegate',
312
+ ' [--mode await|handoff] | remove <to-key> [--kind <kind>]]',
313
+ ' overrides <key> [enable|disable policy|triggers|links]',
314
+ ' (off: teams follow the template exactly; on: teams keep',
315
+ ' their own differences)',
316
+ " skills The source's skills (SKILL.md folders), held by Ekanos:",
317
+ ' list [--team <t>] | show <slug> [--team <t>] |',
318
+ ' push <dir> [--team <t>] (a new version, live at once; created',
319
+ ' on first push, "unchanged" when identical; --team: that team\'s',
320
+ ' own skill, no other team sees it) | pull <slug> [--out <dir>]',
321
+ " runs Run and inspect a team's agents, as the Source admin:",
322
+ ' start <agent-key> --team <slug> (--prompt "…" | --input',
323
+ ' <file.json>) [--follow] | list --team <slug> [--agent <key>] |',
324
+ ' show <run-id> --team <slug> (--json: transcript, tool calls,',
325
+ ' how each was authorized, approvals)',
326
+ " approvals What a team's agent runs wait on: list --team <slug> |",
327
+ ' approve|reject <id> --team <slug> [--reason "…"] |',
328
+ ' edit <id> --team <slug> --body <file> (edit & send a reply draft)',
178
329
  ' use Set this project\'s publish target ("ekanos use <source-slug>")',
179
330
  ' publish Validate, pack and submit the integration to an Ekanos host',
180
331
  ' upgrade Move this toolchain to a coherent target version, with',
@@ -189,7 +340,7 @@ const USAGE = [
189
340
  ' bare "ekanos upgrade" MUTATES the project (installs the target versions,',
190
341
  ' verifies with validate + the test script, rolls back on any failure).',
191
342
  '',
192
- 'Host resolution (logout, whoami, status, sources, catalog, apps, teams, agents, use, publish, upgrade):',
343
+ 'Host resolution (logout, whoami, status, sources, catalog, apps, teams, reviewers, routes, agents, skills, runs, approvals, use, publish, upgrade):',
193
344
  ' --host, else EKANOS_HOST, else the "host" field in ekanos.json, else the',
194
345
  ' sole stored login. "ekanos publish" saves host and source to ekanos.json.',
195
346
  ' "ekanos login" never reads ekanos.json for a host (--host, else',
@@ -360,6 +511,7 @@ export async function run(argv, options = {}) {
360
511
  ask: options.ask,
361
512
  askSecret: options.askSecret,
362
513
  confirm: options.confirm,
514
+ noWait: parsed.flags['no-wait'] === true,
363
515
  });
364
516
  case 'teams':
365
517
  return await runTeams(ctx, {
@@ -367,13 +519,37 @@ export async function run(argv, options = {}) {
367
519
  source: parsed.flags.source,
368
520
  positionals: parsed.positionals,
369
521
  connection: parsed.flags.connection,
522
+ slug: parsed.flags.slug,
523
+ owner: parsed.flags.owner,
524
+ role: parsed.flags.role,
370
525
  yes: parsed.flags.yes === true,
526
+ flags: parsed.flags,
371
527
  dir,
372
528
  env,
373
529
  stdinIsTTY: options.stdinIsTTY,
374
530
  ask: options.ask,
375
531
  askSecret: options.askSecret,
376
532
  });
533
+ case 'reviewers':
534
+ return await runReviewers(ctx, {
535
+ host: parsed.flags.host,
536
+ source: parsed.flags.source,
537
+ positionals: parsed.positionals,
538
+ reach: parsed.flags.reach,
539
+ team: parsed.flags.team,
540
+ dir,
541
+ env,
542
+ });
543
+ case 'routes':
544
+ return await runRoutes(ctx, {
545
+ host: parsed.flags.host,
546
+ source: parsed.flags.source,
547
+ positionals: parsed.positionals,
548
+ label: parsed.flags.label,
549
+ webhook: parsed.flags.webhook,
550
+ dir,
551
+ env,
552
+ });
377
553
  case 'agents':
378
554
  return await runAgents(ctx, {
379
555
  host: parsed.flags.host,
@@ -387,10 +563,54 @@ export async function run(argv, options = {}) {
387
563
  yes: parsed.flags.yes === true,
388
564
  force: parsed.flags.force === true,
389
565
  claude: parsed.flags.claude,
566
+ skills: parsed.flags.skills,
567
+ rest: parsed.positionals.slice(2),
568
+ event: parsed.flags.event,
569
+ filter: parsed.flags.filter,
570
+ disabled: parsed.flags.disabled === true,
571
+ cron: parsed.flags.cron,
572
+ timezone: parsed.flags.timezone,
573
+ kind: parsed.flags.kind,
574
+ mode: parsed.flags.mode,
575
+ reads: parsed.flags.reads,
576
+ writes: parsed.flags.writes,
577
+ publish: parsed.flags.publish === true,
390
578
  dir,
391
579
  env,
392
580
  stdinIsTTY: options.stdinIsTTY,
393
581
  confirm: options.confirm,
582
+ team: parsed.flags.team,
583
+ prompt: parsed.flags.prompt,
584
+ input: parsed.flags.input,
585
+ follow: parsed.flags.follow === true,
586
+ });
587
+ case 'runs':
588
+ case 'approvals':
589
+ return await (command === 'runs' ? runRuns : runApprovals)(ctx, {
590
+ host: parsed.flags.host,
591
+ source: parsed.flags.source,
592
+ positionals: parsed.positionals,
593
+ team: parsed.flags.team,
594
+ agent: parsed.flags.agent,
595
+ prompt: parsed.flags.prompt,
596
+ input: parsed.flags.input,
597
+ follow: parsed.flags.follow === true,
598
+ reason: parsed.flags.reason,
599
+ body: parsed.flags.body,
600
+ dir,
601
+ env,
602
+ sleep: options.sleep,
603
+ });
604
+ case 'skills':
605
+ return await runSkills(ctx, {
606
+ host: parsed.flags.host,
607
+ source: parsed.flags.source,
608
+ subcommand: parsed.positionals[0],
609
+ target: parsed.positionals[1],
610
+ team: parsed.flags.team,
611
+ out: parsed.flags.out,
612
+ dir,
613
+ env,
394
614
  });
395
615
  case 'use':
396
616
  return await runUse(ctx, {