@ekanos/cli 0.14.0 → 0.16.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.
- package/README.md +41 -4
- package/dist/auth/ekanos-api.d.ts +23 -0
- package/dist/auth/ekanos-api.js +33 -6
- package/dist/auth/ekanos-api.js.map +1 -1
- package/dist/commands/agents.d.ts +2 -2
- package/dist/commands/agents.js +14 -20
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/apps.d.ts +11 -3
- package/dist/commands/apps.js +86 -28
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/catalog.d.ts +4 -2
- package/dist/commands/catalog.js +166 -35
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +17 -0
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/runs.d.ts +7 -3
- package/dist/commands/runs.js +24 -6
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +7 -0
- package/dist/commands/scope-notice.js +4 -11
- package/dist/commands/scope-notice.js.map +1 -1
- package/dist/commands/sources-roles.d.ts +5 -0
- package/dist/commands/sources-roles.js +235 -0
- package/dist/commands/sources-roles.js.map +1 -0
- package/dist/commands/sources.d.ts +5 -0
- package/dist/commands/sources.js +6 -1
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/team-agent-readiness.d.ts +23 -17
- package/dist/commands/team-agent-readiness.js +57 -90
- package/dist/commands/team-agent-readiness.js.map +1 -1
- package/dist/commands/team-agents-agents.d.ts +8 -5
- package/dist/commands/team-agents-agents.js +173 -58
- package/dist/commands/team-agents-agents.js.map +1 -1
- package/dist/commands/team-agents-define.d.ts +31 -0
- package/dist/commands/team-agents-define.js +176 -0
- package/dist/commands/team-agents-define.js.map +1 -0
- package/dist/commands/team-agents-mcp.js +112 -10
- package/dist/commands/team-agents-mcp.js.map +1 -1
- package/dist/commands/team-agents-triggers.d.ts +1 -1
- package/dist/commands/team-agents-triggers.js +137 -5
- package/dist/commands/team-agents-triggers.js.map +1 -1
- package/dist/commands/team-agents.d.ts +4 -1
- package/dist/commands/team-agents.js +17 -4
- package/dist/commands/team-agents.js.map +1 -1
- package/dist/commands/team-llm-key.d.ts +14 -0
- package/dist/commands/team-llm-key.js +122 -0
- package/dist/commands/team-llm-key.js.map +1 -0
- package/dist/commands/teams-connect.js +123 -31
- package/dist/commands/teams-connect.js.map +1 -1
- package/dist/commands/teams-lifecycle.d.ts +90 -0
- package/dist/commands/teams-lifecycle.js +457 -0
- package/dist/commands/teams-lifecycle.js.map +1 -0
- package/dist/commands/teams-onboard.d.ts +14 -0
- package/dist/commands/teams-onboard.js +62 -13
- package/dist/commands/teams-onboard.js.map +1 -1
- package/dist/commands/teams-overview.js +7 -3
- package/dist/commands/teams-overview.js.map +1 -1
- package/dist/commands/teams.d.ts +25 -5
- package/dist/commands/teams.js +101 -39
- package/dist/commands/teams.js.map +1 -1
- package/dist/commands/workflows.d.ts +37 -0
- package/dist/commands/workflows.js +589 -0
- package/dist/commands/workflows.js.map +1 -0
- package/dist/connect-fields.d.ts +22 -0
- package/dist/connect-fields.js +115 -0
- package/dist/connect-fields.js.map +1 -0
- package/dist/context.d.ts +12 -0
- package/dist/context.js +32 -9
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +367 -133
- package/dist/index.js.map +1 -1
- package/dist/invocation.d.ts +31 -0
- package/dist/invocation.js +58 -0
- package/dist/invocation.js.map +1 -0
- package/dist/runs-api.js +8 -3
- package/dist/runs-api.js.map +1 -1
- package/dist/safe-fs.d.ts +18 -0
- package/dist/safe-fs.js +57 -0
- package/dist/safe-fs.js.map +1 -1
- package/dist/secret-form.d.ts +48 -0
- package/dist/secret-form.js +212 -0
- package/dist/secret-form.js.map +1 -0
- package/dist/secret-input.d.ts +96 -0
- package/dist/secret-input.js +299 -0
- package/dist/secret-input.js.map +1 -0
- package/dist/team-connect-api.d.ts +78 -3
- package/dist/team-connect-api.js +17 -2
- package/dist/team-connect-api.js.map +1 -1
- package/dist/team-lifecycle-api.d.ts +435 -0
- package/dist/team-lifecycle-api.js +301 -0
- package/dist/team-lifecycle-api.js.map +1 -0
- package/dist/teams-api.d.ts +13 -1
- package/dist/teams-api.js +90 -31
- package/dist/teams-api.js.map +1 -1
- package/dist/unknown-command.d.ts +18 -0
- package/dist/unknown-command.js +50 -0
- package/dist/unknown-command.js.map +1 -0
- package/dist/workflows-api.d.ts +69 -0
- package/dist/workflows-api.js +182 -0
- package/dist/workflows-api.js.map +1 -0
- package/package.json +3 -3
- package/templates/AGENTS.md.tmpl +6 -4
- package/templates/claude-skill.md.tmpl +4 -1
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +56 -22
- package/templates/skills/build-agent/references/agent-json.md +4 -1
- package/templates/skills/build-agent/references/app-setup.md +14 -7
- package/templates/skills/build-agent/references/rollout.md +40 -20
- package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
- package/templates/skills/build-agent/references/triggers.md +4 -3
- package/templates/skills/build-integration/references/widget-design.md +1 -1
- package/templates/skills/ekanos-platform/SKILL.md +77 -23
- package/templates/skills/polish-widgets/references/patterns.md +3 -3
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import { AgentRunListSchema, TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, TeamAgentSkillsSchema, } from '@ekanos/integration-schema';
|
|
1
|
+
import { AgentRunListSchema, TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, TeamAgentSkillsSchema, TeamAgentTagsSchema, } from '@ekanos/integration-schema';
|
|
2
2
|
import { invalidStateError, notFoundError, usageError } from '../errors.js';
|
|
3
|
+
import { cli } from '../invocation.js';
|
|
3
4
|
import { call, listTeamEvents } from '../teams-api.js';
|
|
4
|
-
import { REASON_WORDS, agentReadiness, channelFix, describeAgentReadiness,
|
|
5
|
+
import { REASON_WORDS, agentReadiness, channelFix, describeAgentReadiness, fixLine, liveLine, reachedVia, requirementFix, } from './team-agent-readiness.js';
|
|
5
6
|
import { requireOperand, usageFor } from './team-agents.js';
|
|
7
|
+
import { runTeamAgentDefine } from './team-agents-define.js';
|
|
8
|
+
import { confirmChange } from './teams-lifecycle.js';
|
|
6
9
|
/**
|
|
7
|
-
* `ekanos teams agents list|show|enable|confirm|disable|pin|unpin|policy|skills` —
|
|
10
|
+
* `ekanos teams agents list|show|create|apply|enable|confirm|disable|archive|unarchive|pin|unpin|policy|skills|tags` —
|
|
8
11
|
* a team's provided agents, turned on, versioned, given an approval policy
|
|
9
|
-
* and skills by the Source admin
|
|
12
|
+
* and skills by the Source admin; and the team's own and personal agents,
|
|
13
|
+
* made and changed from an agent.json with `create|apply`
|
|
14
|
+
* (team-agents-define.ts), turned on with `enable`. A personal agent is
|
|
15
|
+
* listed and shown to everyone, and changed by its creator alone. `enable|pin … --draft` puts one team on
|
|
10
16
|
* the template's latest, unpublished version to test it there before
|
|
11
|
-
* publishing. `confirm` (and `--confirm-access`)
|
|
12
|
-
*
|
|
13
|
-
*
|
|
17
|
+
* publishing. `confirm` (and `--confirm-access`) records the caller's own
|
|
18
|
+
* confirmation that it may use its connections in runs no one watches:
|
|
19
|
+
* whoever sets an agent up confirms it (plan 247.2), never a member.
|
|
14
20
|
* `show` answers "is this agent live, and if not, why?" for one agent; `list`
|
|
15
21
|
* ends each agent with the same verdict.
|
|
16
22
|
*/
|
|
17
23
|
export async function runTeamAgentsArea(ctx, run) {
|
|
18
24
|
var _a, _b, _c;
|
|
19
|
-
var _d, _e, _f;
|
|
25
|
+
var _d, _e, _f, _g, _h;
|
|
20
26
|
const team = requireOperand(run.operands[0], 'team slug', 'agents');
|
|
21
27
|
const base = `/api/partner/teams/${encodeURIComponent(team)}/agents`;
|
|
22
28
|
if (run.verb === 'list') {
|
|
@@ -27,14 +33,22 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
27
33
|
source: run.source,
|
|
28
34
|
}));
|
|
29
35
|
const target = { team: list.team.slug, source: run.source };
|
|
36
|
+
const own = (_d = list.ownAgents) !== null && _d !== void 0 ? _d : [];
|
|
30
37
|
return ctx.succeed(Object.assign(Object.assign({ host: run.host }, list), { agents: list.agents.map((entry) => (Object.assign(Object.assign({}, entry), { readiness: agentReadiness(entry, target) }))) }), [
|
|
31
38
|
ctx.ui.result({
|
|
32
|
-
title: list.agents.length === 0
|
|
39
|
+
title: list.agents.length === 0 && own.length === 0
|
|
33
40
|
? `No agents are provided for ${list.team.slug}`
|
|
34
41
|
: `Agents for ${list.team.slug}`,
|
|
35
|
-
tone: list.agents.length === 0 ? 'warn' : 'ok',
|
|
42
|
+
tone: list.agents.length === 0 && own.length === 0 ? 'warn' : 'ok',
|
|
36
43
|
}),
|
|
37
44
|
...list.agents.map((entry) => describeEntry(entry, list.team.slug, run.source)),
|
|
45
|
+
...(own.length > 0
|
|
46
|
+
? [
|
|
47
|
+
`
|
|
48
|
+
The team's own and personal agents:`,
|
|
49
|
+
...own.map((agent) => describeOwnAgent(agent, list.team.slug, run.source)),
|
|
50
|
+
]
|
|
51
|
+
: []),
|
|
38
52
|
list.mcpServers.length > 0
|
|
39
53
|
? `\nMCP servers: ${list.mcpServers.map((server) => `${server.key} (${server.status})`).join(', ')}`
|
|
40
54
|
: '',
|
|
@@ -42,6 +56,9 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
42
56
|
.filter(Boolean)
|
|
43
57
|
.join('\n'));
|
|
44
58
|
}
|
|
59
|
+
if (run.verb === 'create' || run.verb === 'apply') {
|
|
60
|
+
return runTeamAgentDefine(ctx, run, run.verb);
|
|
61
|
+
}
|
|
45
62
|
const key = requireOperand(run.operands[1], 'agent key', 'agents');
|
|
46
63
|
const path = `${base}/${encodeURIComponent(key)}`;
|
|
47
64
|
switch (run.verb) {
|
|
@@ -57,8 +74,8 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
57
74
|
if (draft)
|
|
58
75
|
requireDraftHost(result, 'enabled');
|
|
59
76
|
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${draft
|
|
60
|
-
? `Testing draft v${(
|
|
61
|
-
: `Turned on ${result.slug} for ${result.team.slug}`}${confirmAccess && result.accessConfirmed ? ', and you confirmed it may use
|
|
77
|
+
? `Testing draft v${(_e = result.version) !== null && _e !== void 0 ? _e : '?'} of ${result.slug} on ${result.team.slug}`
|
|
78
|
+
: `Turned on ${result.slug} for ${result.team.slug}`}${confirmAccess && result.accessConfirmed ? ', and you confirmed what it may use' : ''}`, run.source, { confirmRequested: confirmAccess }));
|
|
62
79
|
}
|
|
63
80
|
case 'confirm': {
|
|
64
81
|
expectOperands(run, 2);
|
|
@@ -66,9 +83,7 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
66
83
|
// the host refuses if the version moved (AGENT_VERSION_CHANGED).
|
|
67
84
|
const shown = await shownVersion(ctx, run, base, key);
|
|
68
85
|
const result = await change(run, `${path}/confirm`, 'POST', shown === null ? {} : { expectedVersion: shown });
|
|
69
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, result.
|
|
70
|
-
? `You confirmed the update: ${result.slug} on ${result.team.slug} moved from v${result.advanced.from} to v${result.advanced.to}`
|
|
71
|
-
: `You confirmed ${result.slug} on ${result.team.slug} may use your connections`, run.source, { confirmRequested: true }));
|
|
86
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `You confirmed what ${result.slug} on ${result.team.slug} may use`, run.source, { confirmRequested: true }));
|
|
72
87
|
}
|
|
73
88
|
case 'disable': {
|
|
74
89
|
expectOperands(run, 2);
|
|
@@ -86,7 +101,7 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
86
101
|
draft: true,
|
|
87
102
|
});
|
|
88
103
|
requireDraftHost(result, 'pinned');
|
|
89
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Testing draft v${(
|
|
104
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Testing draft v${(_f = result.version) !== null && _f !== void 0 ? _f : '?'} of ${result.slug} on ${result.team.slug}`, run.source));
|
|
90
105
|
}
|
|
91
106
|
expectOperands(run, 3);
|
|
92
107
|
const version = Number(run.operands[2]);
|
|
@@ -96,13 +111,40 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
96
111
|
: 'Name the version to pin.', `e.g. "ekanos teams agents pin ${team} ${key} 3", or "--draft" to test the unpublished draft. "ekanos agents show ${key}" lists its versions.`);
|
|
97
112
|
}
|
|
98
113
|
const result = await change(run, `${path}/pin`, 'PUT', { version });
|
|
99
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} stays on v${(
|
|
114
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} stays on v${(_g = result.version) !== null && _g !== void 0 ? _g : version} of ${result.slug}`, run.source));
|
|
100
115
|
}
|
|
101
116
|
case 'unpin': {
|
|
102
117
|
expectOperands(run, 2);
|
|
103
118
|
const result = await change(run, `${path}/pin`, 'PUT', { version: null });
|
|
104
119
|
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}`, run.source));
|
|
105
120
|
}
|
|
121
|
+
case 'archive': {
|
|
122
|
+
expectOperands(run, 2);
|
|
123
|
+
// Asked before any request: a script or an agent run passes --yes.
|
|
124
|
+
if (!run.args.yes) {
|
|
125
|
+
await confirmChange(ctx, run.args, {
|
|
126
|
+
what: `Archiving ${key} on ${team} takes it off the team's list: nothing starts it until it is unarchived and turned on again. Its runs, approvals and setup are kept.`,
|
|
127
|
+
command: `${cli()} teams agents archive ${team} ${key} --yes`,
|
|
128
|
+
question: `Archive ${key} on ${team}? [y/N]`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const result = await change(run, `${path}/archive`, 'POST', {});
|
|
132
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), [
|
|
133
|
+
`✓ Archived ${result.slug} on ${result.team.slug}`,
|
|
134
|
+
` Bring it back, paused: ${cli()} teams agents unarchive ${result.team.slug} ${result.slug} --source ${run.source}`,
|
|
135
|
+
].join('\n'));
|
|
136
|
+
}
|
|
137
|
+
case 'unarchive': {
|
|
138
|
+
expectOperands(run, 2);
|
|
139
|
+
const result = await change(run, `${path}/unarchive`, 'POST', {});
|
|
140
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), [
|
|
141
|
+
`✓ Unarchived ${result.slug} on ${result.team.slug}: it is paused`,
|
|
142
|
+
` runs as ${(_h = result.runsAs) !== null && _h !== void 0 ? _h : 'nobody'}`,
|
|
143
|
+
` Next: ${cli()} teams agents enable ${result.team.slug} ${result.slug} --source ${run.source}`,
|
|
144
|
+
].join('\n'));
|
|
145
|
+
}
|
|
146
|
+
case 'tags':
|
|
147
|
+
return tags(ctx, run, team, key, `${path}/tags`);
|
|
106
148
|
case 'policy':
|
|
107
149
|
return policy(ctx, run, team, key, `${path}/policy`);
|
|
108
150
|
case 'skills':
|
|
@@ -119,13 +161,22 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
119
161
|
* activity reads still answers the rest.
|
|
120
162
|
*/
|
|
121
163
|
async function show(ctx, run, base, key) {
|
|
122
|
-
var _a
|
|
164
|
+
var _a;
|
|
165
|
+
var _b, _c, _d;
|
|
123
166
|
const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
|
|
124
167
|
method: 'GET',
|
|
125
168
|
path: base,
|
|
126
169
|
source: run.source,
|
|
127
170
|
}));
|
|
128
171
|
const entry = list.agents.find((candidate) => candidate.key === key);
|
|
172
|
+
// The host finds an agent by its own slug first, as here: a team agent
|
|
173
|
+
// named like a template that is not turned on is the team agent.
|
|
174
|
+
const own = (entry === null || entry === void 0 ? void 0 : entry.agent)
|
|
175
|
+
? undefined
|
|
176
|
+
: (_a = list.ownAgents) === null || _a === void 0 ? void 0 : _a.find((candidate) => candidate.slug === key);
|
|
177
|
+
if (own) {
|
|
178
|
+
return ctx.succeed({ host: run.host, team: list.team, ownAgent: own }, describeOwnAgent(own, list.team.slug, run.source).trimStart());
|
|
179
|
+
}
|
|
129
180
|
if (!entry) {
|
|
130
181
|
throw notFoundError(`No agent "${key}" is provided for ${list.team.slug}.`, `"ekanos teams agents list ${list.team.slug}" lists the agents provided for it.`);
|
|
131
182
|
}
|
|
@@ -148,13 +199,13 @@ async function show(ctx, run, base, key) {
|
|
|
148
199
|
team: list.team,
|
|
149
200
|
agent: entry,
|
|
150
201
|
readiness,
|
|
151
|
-
lastRun: (
|
|
202
|
+
lastRun: (_b = runs === null || runs === void 0 ? void 0 : runs.runs[0]) !== null && _b !== void 0 ? _b : null,
|
|
152
203
|
recentEvents: events
|
|
153
204
|
? events.events.filter((event) => { var _a; return (_a = entry.agent) === null || _a === void 0 ? void 0 : _a.triggers.some((trigger) => trigger.eventId === event.eventId); })
|
|
154
205
|
: null,
|
|
155
206
|
}, describeAgentReadiness(entry, target, readiness, {
|
|
156
|
-
runs: (
|
|
157
|
-
events: (
|
|
207
|
+
runs: (_c = runs === null || runs === void 0 ? void 0 : runs.runs) !== null && _c !== void 0 ? _c : null,
|
|
208
|
+
events: (_d = events === null || events === void 0 ? void 0 : events.events) !== null && _d !== void 0 ? _d : null,
|
|
158
209
|
}, list.scope));
|
|
159
210
|
}
|
|
160
211
|
/** A read `show` can do without: on failure, say so and carry on. */
|
|
@@ -226,6 +277,57 @@ async function skills(ctx, run, team, key, path) {
|
|
|
226
277
|
const result = await run.client.call((token) => call(run.host, token, TeamAgentSkillsSchema, Object.assign({ method: change ? 'PUT' : 'GET', path, source: run.source }, (change ? { body: change } : {}))));
|
|
227
278
|
return ctx.succeed(Object.assign({ host: run.host }, result), describeSkills(ctx, result, change));
|
|
228
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* `teams agents tags <team> <key> [add|remove <tag>]` — the labels that
|
|
282
|
+
* organize the team's agents; they grant nothing. A tag the team does not
|
|
283
|
+
* have yet is made when it is added, as the app's New tag makes it.
|
|
284
|
+
*/
|
|
285
|
+
async function tags(ctx, run, team, key, path) {
|
|
286
|
+
const [action, tag, extra] = run.operands.slice(2);
|
|
287
|
+
if (extra !== undefined) {
|
|
288
|
+
throw usageError(`Unexpected argument "${extra}".`, 'Quote a tag name with spaces, e.g. "Customer support".');
|
|
289
|
+
}
|
|
290
|
+
let change = null;
|
|
291
|
+
if (action === 'add' || action === 'remove') {
|
|
292
|
+
if (!(tag === null || tag === void 0 ? void 0 : tag.trim())) {
|
|
293
|
+
throw usageError(`tags ${action} needs a tag.`, `e.g. ${cli()} teams agents tags ${team} ${key} ${action} "Customer support"`);
|
|
294
|
+
}
|
|
295
|
+
change = { [action]: tag.trim() };
|
|
296
|
+
}
|
|
297
|
+
else if (action !== undefined) {
|
|
298
|
+
throw usageError(`Unknown tags action "${action}".`, usageFor('agents'));
|
|
299
|
+
}
|
|
300
|
+
const result = await run.client.call((token) => call(run.host, token, TeamAgentTagsSchema, Object.assign({ method: change ? 'PUT' : 'GET', path, source: run.source }, (change ? { body: change } : {}))));
|
|
301
|
+
const title = (change === null || change === void 0 ? void 0 : change.add)
|
|
302
|
+
? `Tagged ${result.slug} on ${result.team.slug} "${change.add}"`
|
|
303
|
+
: (change === null || change === void 0 ? void 0 : change.remove)
|
|
304
|
+
? `Took the tag "${change.remove}" off ${result.slug} on ${result.team.slug}`
|
|
305
|
+
: `Tags of ${result.slug} on ${result.team.slug}`;
|
|
306
|
+
const lines = [
|
|
307
|
+
ctx.ui.result({
|
|
308
|
+
title,
|
|
309
|
+
tone: 'ok',
|
|
310
|
+
rows: [
|
|
311
|
+
[
|
|
312
|
+
'tags',
|
|
313
|
+
result.tags.length === 0
|
|
314
|
+
? 'none'
|
|
315
|
+
: result.tags.map((item) => item.name).join(', '),
|
|
316
|
+
],
|
|
317
|
+
],
|
|
318
|
+
notes: result.createdTag
|
|
319
|
+
? [
|
|
320
|
+
`${result.team.slug} had no tag "${result.createdTag.name}": it was made.`,
|
|
321
|
+
]
|
|
322
|
+
: [],
|
|
323
|
+
}),
|
|
324
|
+
];
|
|
325
|
+
const others = result.teamTags.filter((item) => !result.tags.some((on) => on.slug === item.slug));
|
|
326
|
+
if (!change && others.length > 0) {
|
|
327
|
+
lines.push(`\nThe team's other tags: ${others.map((item) => item.name).join(', ')}`);
|
|
328
|
+
}
|
|
329
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), lines.join('\n'));
|
|
330
|
+
}
|
|
229
331
|
function describeSkills(ctx, result, change) {
|
|
230
332
|
const [verb, slug] = (change === null || change === void 0 ? void 0 : change.add)
|
|
231
333
|
? ['Attached', change.add[0]]
|
|
@@ -254,7 +356,6 @@ function describeSkills(ctx, result, change) {
|
|
|
254
356
|
]))}`;
|
|
255
357
|
}
|
|
256
358
|
function describePolicy(ctx, policy, changed, source) {
|
|
257
|
-
var _a;
|
|
258
359
|
// Absent from an older host: say nothing rather than guess.
|
|
259
360
|
const unconfirmed = policy.accessConfirmed === false;
|
|
260
361
|
const head = ctx.ui.result({
|
|
@@ -271,7 +372,7 @@ function describePolicy(ctx, policy, changed, source) {
|
|
|
271
372
|
...(policy.lockedReason ? [policy.lockedReason] : []),
|
|
272
373
|
...(unconfirmed
|
|
273
374
|
? [
|
|
274
|
-
`Not confirmed: until
|
|
375
|
+
`Not confirmed: until you or one of the team's agent managers confirms what it may use, it uses only what needs no confirmation (a looser policy drops a confirmation). Confirm it as yourself with --confirm-access on the change, or for a provided agent ${confirmCommand(policy.team.slug, policy.key, source)}; a team manager can also confirm on its page in the app`,
|
|
275
376
|
]
|
|
276
377
|
: []),
|
|
277
378
|
],
|
|
@@ -287,28 +388,27 @@ function describePolicy(ctx, policy, changed, source) {
|
|
|
287
388
|
]))}`;
|
|
288
389
|
}
|
|
289
390
|
/**
|
|
290
|
-
* The version `confirm` is about to approve — the one
|
|
291
|
-
*
|
|
292
|
-
*
|
|
391
|
+
* The version `confirm` is about to approve — the one it runs — printed
|
|
392
|
+
* before it is sent, so the person confirms what they saw. Null when the
|
|
393
|
+
* team's agent has no version to name.
|
|
293
394
|
*/
|
|
294
395
|
async function shownVersion(ctx, run, base, key) {
|
|
295
|
-
var _a;
|
|
296
|
-
var
|
|
396
|
+
var _a, _b;
|
|
397
|
+
var _c;
|
|
297
398
|
const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
|
|
298
399
|
method: 'GET',
|
|
299
400
|
path: base,
|
|
300
401
|
source: run.source,
|
|
301
402
|
}));
|
|
302
|
-
const
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
ctx.log(`Confirming v${agent.held.waiting} of ${key} on ${list.team.slug}: ${describeHold(agent.held)}. It runs v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} until then.`);
|
|
307
|
-
return agent.held.waiting;
|
|
403
|
+
const own = (_a = list.ownAgents) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.slug === key);
|
|
404
|
+
if (own) {
|
|
405
|
+
ctx.log(`Confirming what ${key} v${own.version} on ${list.team.slug} may use (it runs as ${(_c = own.createdBy) !== null && _c !== void 0 ? _c : 'nobody'}).`);
|
|
406
|
+
return own.version;
|
|
308
407
|
}
|
|
309
|
-
|
|
408
|
+
const agent = (_b = list.agents.find((entry) => entry.key === key)) === null || _b === void 0 ? void 0 : _b.agent;
|
|
409
|
+
if (!agent || agent.version === null)
|
|
310
410
|
return null;
|
|
311
|
-
ctx.log(`Confirming ${key} v${agent.version} on ${list.team.slug} may use
|
|
411
|
+
ctx.log(`Confirming what ${key} v${agent.version} on ${list.team.slug} may use${agent.runsAs ? ` (it runs as ${agent.runsAs})` : ''}.`);
|
|
312
412
|
return agent.version;
|
|
313
413
|
}
|
|
314
414
|
function change(run, path, method, body) {
|
|
@@ -320,7 +420,7 @@ function change(run, path, method, body) {
|
|
|
320
420
|
}));
|
|
321
421
|
}
|
|
322
422
|
function describeEntry(entry, team, source) {
|
|
323
|
-
var _a, _b, _c
|
|
423
|
+
var _a, _b, _c;
|
|
324
424
|
const readiness = agentReadiness(entry, { team, source });
|
|
325
425
|
if (!entry.agent) {
|
|
326
426
|
return `\n${entry.key} — ${entry.name}\n off · v${(_a = entry.publishedVersion) !== null && _a !== void 0 ? _a : '?'} published\n ${liveLine(readiness)} · Next: ${readiness.next}`;
|
|
@@ -329,29 +429,49 @@ function describeEntry(entry, team, source) {
|
|
|
329
429
|
const version = versionLabel(agent);
|
|
330
430
|
const lines = [
|
|
331
431
|
`\n${entry.key} — ${entry.name}`,
|
|
332
|
-
` ${agent.status} · ${version} · runs as ${(_b = agent.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}${agent.accessConfirmed ? '' : ` · access not confirmed (${(
|
|
333
|
-
...(agent.held
|
|
334
|
-
? [
|
|
335
|
-
` ! held on v${(_d = agent.version) !== null && _d !== void 0 ? _d : '?'}: v${agent.held.waiting} ${describeHold(agent.held)}. It keeps running v${(_e = agent.version) !== null && _e !== void 0 ? _e : '?'} until ${(_f = agent.runsAs) !== null && _f !== void 0 ? _f : 'the person it runs as'} confirms: ${confirmCommand(team, entry.key, source)}`,
|
|
336
|
-
]
|
|
337
|
-
: []),
|
|
432
|
+
` ${agent.status} · ${version} · runs as ${(_b = agent.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}${agent.accessConfirmed ? '' : ` · access not confirmed (${confirmCommand(team, entry.key, source)})`}`,
|
|
338
433
|
` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
|
|
339
434
|
` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,
|
|
340
435
|
];
|
|
341
436
|
lines.push(...requirementLines(agent.requirements, agent.missing, team, source));
|
|
342
437
|
if (agent.draft)
|
|
343
438
|
lines.push(...draftLines(team, entry.key));
|
|
344
|
-
lines.push(...channelLines((
|
|
345
|
-
lines.push(` ${liveLine(readiness
|
|
439
|
+
lines.push(...channelLines((_c = agent.channels) !== null && _c !== void 0 ? _c : [], team, source));
|
|
440
|
+
lines.push(` ${liveLine(readiness)}${readiness.next ? ` · Next: ${readiness.next}` : ''}`);
|
|
441
|
+
return lines.join('\n');
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* One of the team's own agents, or a personal one: whose it is, its version
|
|
445
|
+
* (what `apply --base-version` names), its triggers, and the next step.
|
|
446
|
+
*/
|
|
447
|
+
function describeOwnAgent(agent, team, source) {
|
|
448
|
+
var _a, _b;
|
|
449
|
+
const personal = agent.ownership === 'personal';
|
|
450
|
+
const whose = personal
|
|
451
|
+
? `personal agent of ${agent.yours ? 'yours' : ((_a = agent.createdBy) !== null && _a !== void 0 ? _a : 'a former member')}`
|
|
452
|
+
: `team agent · runs as ${(_b = agent.createdBy) !== null && _b !== void 0 ? _b : 'nobody'}`;
|
|
453
|
+
const lines = [
|
|
454
|
+
`
|
|
455
|
+
${agent.slug} — ${agent.name}`,
|
|
456
|
+
` ${agent.status} · v${agent.version} · ${whose}${agent.accessConfirmed ? '' : ' · access not confirmed'}`,
|
|
457
|
+
` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
|
|
458
|
+
];
|
|
459
|
+
if (personal && !agent.yours) {
|
|
460
|
+
lines.push(' Only its creator changes it, runs it, decides its approvals or reads its runs.');
|
|
461
|
+
}
|
|
462
|
+
else if (agent.status !== 'active') {
|
|
463
|
+
lines.push(` Next: ekanos teams agents enable ${team} ${agent.slug} --source ${source}`);
|
|
464
|
+
}
|
|
465
|
+
else if (!agent.accessConfirmed) {
|
|
466
|
+
lines.push(` Next: ${confirmCommand(team, agent.slug, source)}`);
|
|
467
|
+
}
|
|
346
468
|
return lines.join('\n');
|
|
347
469
|
}
|
|
348
470
|
function versionLabel(agent) {
|
|
349
|
-
var _a, _b
|
|
471
|
+
var _a, _b;
|
|
350
472
|
if (agent.draft)
|
|
351
473
|
return `draft v${(_a = agent.version) !== null && _a !== void 0 ? _a : '?'} (testing, unpublished)`;
|
|
352
|
-
|
|
353
|
-
return `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} (held, v${agent.held.waiting} waiting for confirmation)`;
|
|
354
|
-
return `v${(_c = agent.version) !== null && _c !== void 0 ? _c : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
|
|
474
|
+
return `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
|
|
355
475
|
}
|
|
356
476
|
/** What testing a draft on a team means, and the next step. */
|
|
357
477
|
function draftLines(team, key) {
|
|
@@ -416,7 +536,7 @@ export function channelLines(channels, team, source) {
|
|
|
416
536
|
]; });
|
|
417
537
|
}
|
|
418
538
|
function describeChange(result, title, source, options = {}) {
|
|
419
|
-
var _a, _b
|
|
539
|
+
var _a, _b;
|
|
420
540
|
const covers = result.access ? describeAccess(result.access) : null;
|
|
421
541
|
const lines = [
|
|
422
542
|
`${options.confirmRequested && !result.accessConfirmed ? '!' : '✓'} ${title}`,
|
|
@@ -424,12 +544,7 @@ function describeChange(result, title, source, options = {}) {
|
|
|
424
544
|
];
|
|
425
545
|
if (result.accessConfirmed) {
|
|
426
546
|
if (covers) {
|
|
427
|
-
lines.push(result.
|
|
428
|
-
? ` Now allowed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`
|
|
429
|
-
: ` Confirmed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`);
|
|
430
|
-
}
|
|
431
|
-
if (result.held) {
|
|
432
|
-
lines.push(` Held on v${(_b = result.version) !== null && _b !== void 0 ? _b : '?'}: v${result.held.waiting} ${describeHold(result.held)}. ${(_c = result.runsAs) !== null && _c !== void 0 ? _c : 'The person it runs as'} moves it by confirming: ${confirmCommand(result.team.slug, result.key, source)}`);
|
|
547
|
+
lines.push(` Confirmed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`);
|
|
433
548
|
}
|
|
434
549
|
}
|
|
435
550
|
else {
|
|
@@ -437,12 +552,12 @@ function describeChange(result, title, source, options = {}) {
|
|
|
437
552
|
// An older host ignores confirmAccess rather than refusing it.
|
|
438
553
|
lines.push(' This host did not record the confirmation: it may not support confirming from the CLI yet.');
|
|
439
554
|
}
|
|
440
|
-
lines.push(` Not confirmed: until
|
|
555
|
+
lines.push(` Not confirmed: until you or one of the team's agent managers confirms what it may use${covers ? ` (${result.runsAs ? `${result.runsAs}'s` : 'its'} connections, to ${covers})` : ''}, it uses only what needs no confirmation.`, ` → ${confirmCommand(result.team.slug, result.key, source)}`);
|
|
441
556
|
}
|
|
442
557
|
lines.push(...requirementLines([], result.missing, result.team.slug, source));
|
|
443
558
|
if (result.draft)
|
|
444
559
|
lines.push(...draftLines(result.team.slug, result.key));
|
|
445
|
-
lines.push(...channelLines((
|
|
560
|
+
lines.push(...channelLines((_b = result.channels) !== null && _b !== void 0 ? _b : [], result.team.slug, source));
|
|
446
561
|
return lines.join('\n');
|
|
447
562
|
}
|
|
448
563
|
/** What a confirmation covers, in words: whose connections, to what. */
|