@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.
Files changed (115) hide show
  1. package/README.md +41 -4
  2. package/dist/auth/ekanos-api.d.ts +23 -0
  3. package/dist/auth/ekanos-api.js +33 -6
  4. package/dist/auth/ekanos-api.js.map +1 -1
  5. package/dist/commands/agents.d.ts +2 -2
  6. package/dist/commands/agents.js +14 -20
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/apps.d.ts +11 -3
  9. package/dist/commands/apps.js +86 -28
  10. package/dist/commands/apps.js.map +1 -1
  11. package/dist/commands/catalog.d.ts +4 -2
  12. package/dist/commands/catalog.js +166 -35
  13. package/dist/commands/catalog.js.map +1 -1
  14. package/dist/commands/login.d.ts +2 -0
  15. package/dist/commands/login.js +17 -0
  16. package/dist/commands/login.js.map +1 -1
  17. package/dist/commands/runs.d.ts +7 -3
  18. package/dist/commands/runs.js +24 -6
  19. package/dist/commands/runs.js.map +1 -1
  20. package/dist/commands/scope-notice.d.ts +7 -0
  21. package/dist/commands/scope-notice.js +4 -11
  22. package/dist/commands/scope-notice.js.map +1 -1
  23. package/dist/commands/sources-roles.d.ts +5 -0
  24. package/dist/commands/sources-roles.js +235 -0
  25. package/dist/commands/sources-roles.js.map +1 -0
  26. package/dist/commands/sources.d.ts +5 -0
  27. package/dist/commands/sources.js +6 -1
  28. package/dist/commands/sources.js.map +1 -1
  29. package/dist/commands/team-agent-readiness.d.ts +23 -17
  30. package/dist/commands/team-agent-readiness.js +57 -90
  31. package/dist/commands/team-agent-readiness.js.map +1 -1
  32. package/dist/commands/team-agents-agents.d.ts +8 -5
  33. package/dist/commands/team-agents-agents.js +173 -58
  34. package/dist/commands/team-agents-agents.js.map +1 -1
  35. package/dist/commands/team-agents-define.d.ts +31 -0
  36. package/dist/commands/team-agents-define.js +176 -0
  37. package/dist/commands/team-agents-define.js.map +1 -0
  38. package/dist/commands/team-agents-mcp.js +112 -10
  39. package/dist/commands/team-agents-mcp.js.map +1 -1
  40. package/dist/commands/team-agents-triggers.d.ts +1 -1
  41. package/dist/commands/team-agents-triggers.js +137 -5
  42. package/dist/commands/team-agents-triggers.js.map +1 -1
  43. package/dist/commands/team-agents.d.ts +4 -1
  44. package/dist/commands/team-agents.js +17 -4
  45. package/dist/commands/team-agents.js.map +1 -1
  46. package/dist/commands/team-llm-key.d.ts +14 -0
  47. package/dist/commands/team-llm-key.js +122 -0
  48. package/dist/commands/team-llm-key.js.map +1 -0
  49. package/dist/commands/teams-connect.js +123 -31
  50. package/dist/commands/teams-connect.js.map +1 -1
  51. package/dist/commands/teams-lifecycle.d.ts +90 -0
  52. package/dist/commands/teams-lifecycle.js +457 -0
  53. package/dist/commands/teams-lifecycle.js.map +1 -0
  54. package/dist/commands/teams-onboard.d.ts +14 -0
  55. package/dist/commands/teams-onboard.js +62 -13
  56. package/dist/commands/teams-onboard.js.map +1 -1
  57. package/dist/commands/teams-overview.js +7 -3
  58. package/dist/commands/teams-overview.js.map +1 -1
  59. package/dist/commands/teams.d.ts +25 -5
  60. package/dist/commands/teams.js +101 -39
  61. package/dist/commands/teams.js.map +1 -1
  62. package/dist/commands/workflows.d.ts +37 -0
  63. package/dist/commands/workflows.js +589 -0
  64. package/dist/commands/workflows.js.map +1 -0
  65. package/dist/connect-fields.d.ts +22 -0
  66. package/dist/connect-fields.js +115 -0
  67. package/dist/connect-fields.js.map +1 -0
  68. package/dist/context.d.ts +12 -0
  69. package/dist/context.js +32 -9
  70. package/dist/context.js.map +1 -1
  71. package/dist/index.d.ts +13 -0
  72. package/dist/index.js +367 -133
  73. package/dist/index.js.map +1 -1
  74. package/dist/invocation.d.ts +31 -0
  75. package/dist/invocation.js +58 -0
  76. package/dist/invocation.js.map +1 -0
  77. package/dist/runs-api.js +8 -3
  78. package/dist/runs-api.js.map +1 -1
  79. package/dist/safe-fs.d.ts +18 -0
  80. package/dist/safe-fs.js +57 -0
  81. package/dist/safe-fs.js.map +1 -1
  82. package/dist/secret-form.d.ts +48 -0
  83. package/dist/secret-form.js +212 -0
  84. package/dist/secret-form.js.map +1 -0
  85. package/dist/secret-input.d.ts +96 -0
  86. package/dist/secret-input.js +299 -0
  87. package/dist/secret-input.js.map +1 -0
  88. package/dist/team-connect-api.d.ts +78 -3
  89. package/dist/team-connect-api.js +17 -2
  90. package/dist/team-connect-api.js.map +1 -1
  91. package/dist/team-lifecycle-api.d.ts +435 -0
  92. package/dist/team-lifecycle-api.js +301 -0
  93. package/dist/team-lifecycle-api.js.map +1 -0
  94. package/dist/teams-api.d.ts +13 -1
  95. package/dist/teams-api.js +90 -31
  96. package/dist/teams-api.js.map +1 -1
  97. package/dist/unknown-command.d.ts +18 -0
  98. package/dist/unknown-command.js +50 -0
  99. package/dist/unknown-command.js.map +1 -0
  100. package/dist/workflows-api.d.ts +69 -0
  101. package/dist/workflows-api.js +182 -0
  102. package/dist/workflows-api.js.map +1 -0
  103. package/package.json +3 -3
  104. package/templates/AGENTS.md.tmpl +6 -4
  105. package/templates/claude-skill.md.tmpl +4 -1
  106. package/templates/package.json.tmpl +4 -4
  107. package/templates/skills/build-agent/SKILL.md +56 -22
  108. package/templates/skills/build-agent/references/agent-json.md +4 -1
  109. package/templates/skills/build-agent/references/app-setup.md +14 -7
  110. package/templates/skills/build-agent/references/rollout.md +40 -20
  111. package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
  112. package/templates/skills/build-agent/references/triggers.md +4 -3
  113. package/templates/skills/build-integration/references/widget-design.md +1 -1
  114. package/templates/skills/ekanos-platform/SKILL.md +77 -23
  115. 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, describeHold, fixLine, liveLine, reachedVia, requirementFix, } from './team-agent-readiness.js';
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. `enable|pin … --draft` puts one team on
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`) is the one thing only the
12
- * person the agent runs as can do: consent, as themselves, that it may use
13
- * their connections in runs no one watches.
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${(_d = result.version) !== null && _d !== void 0 ? _d : '?'} of ${result.slug} on ${result.team.slug}`
61
- : `Turned on ${result.slug} for ${result.team.slug}`}${confirmAccess && result.accessConfirmed ? ', and you confirmed it may use your connections' : ''}`, run.source, { confirmRequested: confirmAccess }));
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.advanced
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${(_e = result.version) !== null && _e !== void 0 ? _e : '?'} of ${result.slug} on ${result.team.slug}`, run.source));
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${(_f = result.version) !== null && _f !== void 0 ? _f : version} of ${result.slug}`, run.source));
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, _b, _c;
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: (_a = runs === null || runs === void 0 ? void 0 : runs.runs[0]) !== null && _a !== void 0 ? _a : null,
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: (_b = runs === null || runs === void 0 ? void 0 : runs.runs) !== null && _b !== void 0 ? _b : null,
157
- events: (_c = events === null || events === void 0 ? void 0 : events.events) !== null && _c !== void 0 ? _c : null,
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 ${(_a = policy.runsAs) !== null && _a !== void 0 ? _a : 'the person it runs as'} confirms it may use their connections, it uses only what needs no confirmation (a looser policy drops a confirmation). They run: ${confirmCommand(policy.team.slug, policy.key, source)} — or, for the team's own agent, confirm on its page in the app`,
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 waiting on a held
291
- * agent, else the one it runs — printed before it is sent, so the person
292
- * confirms what they saw. Null when the team's agent has no version to name.
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 _b;
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 agent = (_a = list.agents.find((entry) => entry.key === key)) === null || _a === void 0 ? void 0 : _a.agent;
303
- if (!agent)
304
- return null;
305
- if (agent.held) {
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
- if (agent.version === null)
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 your connections.`);
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, _d, _e, _f, _g;
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 (${(_c = agent.runsAs) !== null && _c !== void 0 ? _c : 'they'}: ekanos teams agents confirm ${team} ${entry.key})`}`,
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((_g = agent.channels) !== null && _g !== void 0 ? _g : [], team, source));
345
- lines.push(` ${liveLine(readiness, agent)}${readiness.next ? ` · Next: ${readiness.next}` : ''}`);
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, _c;
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
- if (agent.held)
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, _c, _d, _e, _f;
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.advanced
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 ${(_d = result.runsAs) !== null && _d !== void 0 ? _d : 'the person it runs as'} confirms it may use their connections${covers ? ` (to ${covers})` : ''}, it uses only what needs no confirmation.`, ` → ${(_e = result.runsAs) !== null && _e !== void 0 ? _e : 'They'}, as themselves: ${confirmCommand(result.team.slug, result.key, source)}`);
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((_f = result.channels) !== null && _f !== void 0 ? _f : [], result.team.slug, source));
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. */