@ekanos/cli 0.13.0 → 0.15.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 +25 -8
- package/dist/agents-api.d.ts +11 -2
- package/dist/agents-api.js +39 -3
- package/dist/agents-api.js.map +1 -1
- package/dist/apps-api.js +2 -2
- package/dist/apps-api.js.map +1 -1
- package/dist/auth/ekanos-api.d.ts +16 -2
- package/dist/auth/ekanos-api.js +101 -15
- package/dist/auth/ekanos-api.js.map +1 -1
- package/dist/auth/host-trust.d.ts +46 -0
- package/dist/auth/host-trust.js +79 -0
- package/dist/auth/host-trust.js.map +1 -0
- package/dist/auth/session.d.ts +10 -1
- package/dist/auth/session.js +28 -28
- package/dist/auth/session.js.map +1 -1
- package/dist/commands/agents-edit.d.ts +6 -2
- package/dist/commands/agents-edit.js +57 -26
- package/dist/commands/agents-edit.js.map +1 -1
- package/dist/commands/agents.d.ts +13 -2
- package/dist/commands/agents.js +140 -35
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +16 -12
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/catalog.js +7 -6
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/knowledge.d.ts +19 -0
- package/dist/commands/knowledge.js +119 -27
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.js +30 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +9 -1
- package/dist/commands/logout.js +56 -7
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/publish.js +3 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/reviewers.d.ts +2 -0
- package/dist/commands/reviewers.js +7 -3
- package/dist/commands/reviewers.js.map +1 -1
- package/dist/commands/routes.d.ts +2 -0
- package/dist/commands/routes.js +42 -9
- package/dist/commands/routes.js.map +1 -1
- package/dist/commands/runs.d.ts +13 -2
- package/dist/commands/runs.js +99 -16
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +21 -0
- package/dist/commands/scope-notice.js +35 -0
- package/dist/commands/scope-notice.js.map +1 -0
- package/dist/commands/skills.d.ts +7 -1
- package/dist/commands/skills.js +80 -24
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/sources.d.ts +1 -1
- package/dist/commands/sources.js +126 -12
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/status.js +5 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/team-agent-readiness.d.ts +49 -0
- package/dist/commands/team-agent-readiness.js +308 -0
- package/dist/commands/team-agent-readiness.js.map +1 -0
- package/dist/commands/team-agents-agents.d.ts +24 -3
- package/dist/commands/team-agents-agents.js +314 -35
- package/dist/commands/team-agents-agents.js.map +1 -1
- package/dist/commands/team-agents-mcp.js +32 -3
- package/dist/commands/team-agents-mcp.js.map +1 -1
- package/dist/commands/team-agents-triggers.js +230 -55
- package/dist/commands/team-agents-triggers.js.map +1 -1
- package/dist/commands/team-agents.d.ts +3 -1
- package/dist/commands/team-agents.js +27 -7
- package/dist/commands/team-agents.js.map +1 -1
- package/dist/commands/teams-channel-install.d.ts +24 -0
- package/dist/commands/teams-channel-install.js +94 -0
- package/dist/commands/teams-channel-install.js.map +1 -0
- package/dist/commands/teams-connect.d.ts +41 -0
- package/dist/commands/teams-connect.js +212 -57
- package/dist/commands/teams-connect.js.map +1 -1
- package/dist/commands/teams-events.d.ts +12 -0
- package/dist/commands/teams-events.js +138 -0
- package/dist/commands/teams-events.js.map +1 -0
- package/dist/commands/teams-onboard.d.ts +11 -3
- package/dist/commands/teams-onboard.js +60 -7
- package/dist/commands/teams-onboard.js.map +1 -1
- package/dist/commands/teams-overview.d.ts +11 -0
- package/dist/commands/teams-overview.js +160 -0
- package/dist/commands/teams-overview.js.map +1 -0
- package/dist/commands/teams-scope.d.ts +10 -0
- package/dist/commands/teams-scope.js +109 -0
- package/dist/commands/teams-scope.js.map +1 -0
- package/dist/commands/teams.d.ts +4 -2
- package/dist/commands/teams.js +113 -14
- package/dist/commands/teams.js.map +1 -1
- package/dist/commands/upgrade.js +12 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/commands/use.js +2 -2
- package/dist/commands/use.js.map +1 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/connections-api.js +1 -1
- package/dist/connections-api.js.map +1 -1
- package/dist/delegate.js +11 -4
- package/dist/delegate.js.map +1 -1
- package/dist/harness-scaffold.js +12 -0
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +682 -167
- package/dist/index.js.map +1 -1
- package/dist/knowledge-api.d.ts +46 -0
- package/dist/knowledge-api.js +32 -1
- package/dist/knowledge-api.js.map +1 -1
- package/dist/open-url.d.ts +16 -0
- package/dist/open-url.js +73 -0
- package/dist/open-url.js.map +1 -0
- package/dist/parse-argv.d.ts +2 -0
- package/dist/parse-argv.js.map +1 -1
- package/dist/publish-api.d.ts +2 -1
- package/dist/publish-api.js +4 -3
- package/dist/publish-api.js.map +1 -1
- package/dist/pull-write.d.ts +27 -0
- package/dist/pull-write.js +60 -0
- package/dist/pull-write.js.map +1 -0
- package/dist/routes-api.d.ts +3 -0
- package/dist/routes-api.js +9 -4
- package/dist/routes-api.js.map +1 -1
- package/dist/runs-api.d.ts +7 -1
- package/dist/runs-api.js +21 -6
- package/dist/runs-api.js.map +1 -1
- package/dist/safe-fs.d.ts +2 -0
- package/dist/safe-fs.js +12 -6
- package/dist/safe-fs.js.map +1 -1
- package/dist/secret-file.d.ts +17 -0
- package/dist/secret-file.js +69 -0
- package/dist/secret-file.js.map +1 -0
- package/dist/skills-api.d.ts +10 -2
- package/dist/skills-api.js +37 -2
- package/dist/skills-api.js.map +1 -1
- package/dist/source-products-api.d.ts +4 -0
- package/dist/source-products-api.js +14 -4
- package/dist/source-products-api.js.map +1 -1
- package/dist/source-target.js +2 -1
- package/dist/source-target.js.map +1 -1
- package/dist/sources-api.d.ts +2 -1
- package/dist/sources-api.js +3 -2
- package/dist/sources-api.js.map +1 -1
- package/dist/team-connect-api.d.ts +44 -2
- package/dist/team-connect-api.js +19 -7
- package/dist/team-connect-api.js.map +1 -1
- package/dist/teams-api.d.ts +41 -1
- package/dist/teams-api.js +95 -19
- package/dist/teams-api.js.map +1 -1
- package/dist/toolchain-api.d.ts +9 -0
- package/dist/toolchain-api.js +17 -2
- package/dist/toolchain-api.js.map +1 -1
- package/dist/toolchain-resolve.d.ts +3 -0
- package/dist/toolchain-resolve.js +15 -1
- package/dist/toolchain-resolve.js.map +1 -1
- package/dist/toolchain.d.ts +6 -0
- package/dist/toolchain.js +19 -0
- package/dist/toolchain.js.map +1 -1
- package/dist/update-notice.js +2 -1
- package/dist/update-notice.js.map +1 -1
- package/package.json +2 -2
- package/templates/AGENTS.md.tmpl +6 -1
- package/templates/claude-skill.md.tmpl +5 -0
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +104 -17
- package/templates/skills/build-agent/references/agent-json.md +4 -2
- package/templates/skills/build-agent/references/rollout.md +23 -4
- package/templates/skills/build-agent/references/set-up-an-integration.md +55 -7
- package/templates/skills/build-agent/references/skills.md +20 -1
- package/templates/skills/build-agent/references/triggers.md +47 -11
- package/templates/skills/build-integration/references/widget-design.md +3 -3
- package/templates/skills/ekanos-platform/SKILL.md +45 -16
- package/templates/skills/polish-widgets/references/patterns.md +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-agent-readiness.js","sourceRoot":"","sources":["../../src/commands/team-agent-readiness.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AgentRunSummary,\n ChannelRequirement,\n Requirement,\n TeamAgentEntry,\n TeamAgentHold,\n TeamIntegrationEvent,\n} from '@ekanos/integration-schema';\n\nimport { type ScopeFacts, scopeFix, scopeHiddenWords } from './scope-notice';\n\n/**\n * \"Is this agent live on this team, and if not, why?\" — one answer for\n * `teams agents show` and the summary line of `teams agents list`, built only\n * from what the host already reports (CLI audit 2026-10-19, §3).\n *\n * Live is: on, on a published version, every connection it needs made,\n * access confirmed by someone who sets it up (a team manager or the Source\n * admin, plan 247.2), at least one trigger on, and every trigger's events\n * able to reach it. Each gap is a step with one fix, in the order they have\n * to be done; the first step's fix is \"Next\". A publish holds no team, so\n * there is no update waiting.\n */\n\nconst CLI = 'npx @ekanos/cli';\n\nexport interface ReadinessStep {\n /** What is missing, in words. */\n problem: string;\n /** The one command (or app step) that fixes it. */\n fix: string;\n}\n\nexport interface AgentReadiness {\n live: boolean;\n steps: ReadinessStep[];\n /** The first step's fix; null when there is none. */\n next: string | null;\n}\n\nexport interface ReadinessTarget {\n team: string;\n source: string;\n}\n\nexport function agentReadiness(\n entry: TeamAgentEntry,\n target: ReadinessTarget,\n): AgentReadiness {\n const steps = readinessSteps(entry, target);\n return {\n live: steps.length === 0,\n steps,\n next: steps[0]?.fix ?? null,\n };\n}\n\n/**\n * What a newer version adds over the one a team runs, in words (a publish's\n * report of the teams pinned to another version):\n * \"adds zendesk_update_ticket; lets zendesk_add_tag run without approval\".\n */\nexport function describeHold(hold: TeamAgentHold): string {\n const adds = [\n ...(hold.adds.scope === 'all'\n ? ['every tool of the products it can reach']\n : hold.adds.scope === 'read_only'\n ? ['every read of the products it can reach']\n : []),\n ...hold.adds.products.map((product) => `${product.name} (every tool)`),\n ...hold.adds.tools,\n ];\n const loosens = [\n ...(hold.loosens.writes ? ['writes'] : []),\n ...(hold.loosens.reads ? ['reads'] : []),\n ...hold.loosens.tools,\n ];\n const parts = [\n ...(adds.length > 0 ? [`adds ${adds.join(', ')}`] : []),\n ...(loosens.length > 0\n ? [`lets ${loosens.join(', ')} run without approval`]\n : []),\n ];\n return parts.length > 0 ? parts.join('; ') : 'reaches further';\n}\n\nfunction readinessSteps(\n entry: TeamAgentEntry,\n { team, source }: ReadinessTarget,\n): ReadinessStep[] {\n const enable = `${CLI} teams agents enable ${team} ${entry.key} --source ${source}`;\n const agent = entry.agent;\n if (!agent) return [{ problem: `off for ${team}`, fix: enable }];\n if (agent.status !== 'active') {\n return [{ problem: `${agent.status} for ${team}`, fix: enable }];\n }\n\n const steps: ReadinessStep[] = [];\n if (agent.draft) {\n // A team testing a draft runs it only when started by hand.\n steps.push({\n problem: `testing unpublished draft v${agent.version ?? '?'}: its triggers do not start it`,\n fix: `${CLI} agents publish ${entry.key} --source ${source}`,\n });\n } else if (agent.version === null) {\n steps.push({\n problem: 'no published version',\n fix: `${CLI} agents publish ${entry.key} --source ${source}`,\n });\n }\n for (const item of agent.missing) {\n steps.push({\n problem: `${item.name}: ${REASON_WORDS[item.reason ?? 'not_connected']}`,\n fix:\n requirementFix(item, team, source) ??\n `${CLI} teams mcp status ${team} ${item.key} --source ${source}`,\n });\n }\n if (!agent.accessConfirmed) {\n steps.push({\n problem: 'nobody has confirmed what it may use',\n // Whoever sets it up confirms, as themselves: the Source admin here,\n // or a team manager in the app (plan 247.2).\n fix: `${CLI} teams agents confirm ${team} ${entry.key} --source ${source} (or a team manager confirms in the app: Agents › ${entry.name} › Setup)`,\n });\n }\n if (!agent.triggers.some((trigger) => trigger.enabled)) {\n steps.push({\n problem: 'no trigger is on, so it only runs when started by hand',\n fix: `${CLI} teams triggers add ${team} ${entry.key} event <event-id> --source ${source} (event ids: ${CLI} catalog --source ${source})`,\n });\n }\n for (const channel of agent.channels ?? []) {\n if (channel.ready) continue;\n steps.push({\n problem: channel.problem ?? `${channel.name} not ready`,\n fix: channelFix(channel, team, source),\n });\n }\n return steps;\n}\n\nexport const REASON_WORDS: Record<\n NonNullable<Requirement['reason']>,\n string\n> = {\n not_connected: 'not connected',\n no_route: 'no route maps the Source connection’s events to this team',\n source_unsupported: 'the integration no longer supports a Source connection',\n source_not_entitled: 'the product is not enabled for the Source',\n source_not_connected: 'the Source connection is not made',\n};\n\n/** The one command that makes a requirement, or null when none can. */\nexport function requirementFix(\n item: Requirement,\n team: string,\n source: string,\n): string | null {\n if (item.kind === 'mcp') return null;\n switch (item.reason) {\n case 'no_route':\n return `${CLI} routes set ${item.key} <value> ${team} --source ${source} (values: ${CLI} routes options ${item.key} --source ${source})`;\n case 'source_not_connected':\n return `${CLI} apps connect ${item.key} --source ${source}`;\n case 'source_not_entitled':\n return `a super-admin enables it for the Source (${CLI} sources products --source ${source})`;\n case 'source_unsupported':\n return `set connections.${item.key}.owner to \"team\" in agent.json, then ${CLI} agents apply`;\n default:\n if (item.connected) return null;\n // A per-person product is the runs-as person's connection, not the\n // caller's: connecting your own leaves the agent missing it.\n return item.via === 'person' && item.viaDetail\n ? `${CLI} teams connect ${team} ${item.key} --as ${item.viaDetail} --source ${source}`\n : `${CLI} teams connect ${team} ${item.key} --source ${source}`;\n }\n}\n\n/** The one command that makes a channel ready, or the app step. */\nexport function channelFix(\n channel: ChannelRequirement,\n team: string,\n source: string,\n): string {\n switch (channel.arrival) {\n case 'team-webhook':\n return `${CLI} teams webhook ${team} ${channel.product} --source ${source}`;\n case 'source-route':\n return channel.webhook\n ? `${CLI} routes set ${channel.product} <value> ${team} --source ${source} (values: ${CLI} routes options ${channel.product} --source ${source})`\n : `${CLI} routes webhook ${channel.product} --source ${source}`;\n default:\n return channel.connectionId\n ? `${CLI} teams connect ${team} ${channel.product} --connection ${channel.connectionId} --source ${source}`\n : channel.key === 'slack' || channel.key === 'linear-app'\n ? `${CLI} teams connect ${team} ${channel.key} --source ${source}`\n : `install it on the agent's Triggers tab in the app`;\n }\n}\n\n/** How the events of a ready channel reach the agent. */\nexport function reachedVia(channel: ChannelRequirement): string {\n switch (channel.arrival) {\n case 'team-webhook':\n return 'team webhook';\n case 'source-route':\n return 'Source webhook, routed';\n default:\n return `${channel.name} installed`;\n }\n}\n\n/** A fix as a line: a command is run in the terminal, an app step is not. */\nexport function fixLine(fix: string): string {\n return fix.startsWith(CLI) ? `in your terminal: ${fix}` : fix;\n}\n\n/** \"Live: yes\" or \"Live: no — N steps left\". */\nexport function liveLine(readiness: AgentReadiness): string {\n const left = readiness.steps.length;\n return readiness.live\n ? 'Live: yes'\n : `Live: no — ${left} step${left === 1 ? '' : 's'} left`;\n}\n\n/* ---------------------------------------------------------------------- */\n/* teams agents show */\n/* ---------------------------------------------------------------------- */\n\n/** What happened lately, read alongside the agent; each part optional. */\nexport interface AgentActivity {\n /** The agent's recent runs, newest first. */\n runs: AgentRunSummary[] | null;\n /** The team's recent integration events, newest first. */\n events: TeamIntegrationEvent[] | null;\n}\n\n/**\n * One line per product, per trigger, then Live and Next. A product the\n * team's product scopes hide from it in the app says so — connected or not,\n * the team cannot see it there (`scope`, the team's scopes).\n */\nexport function describeAgentReadiness(\n entry: TeamAgentEntry,\n target: ReadinessTarget,\n readiness: AgentReadiness,\n activity: AgentActivity,\n scope?: ScopeFacts,\n): string {\n const agent = entry.agent;\n if (!agent) {\n return [\n `${entry.key} on ${target.team} · off · v${entry.publishedVersion ?? '?'} published`,\n ` ${liveLine(readiness)}`,\n ` Next: ${readiness.next}`,\n ].join('\\n');\n }\n\n const head = [\n `${entry.key} on ${target.team}`,\n agent.draft\n ? `draft v${agent.version ?? '?'} (testing, unpublished)`\n : `v${agent.version ?? '?'} (${agent.pinned ? 'pinned' : 'following'})`,\n ...(agent.status === 'active' ? [] : [agent.status]),\n `runs as ${agent.runsAs ?? 'nobody'}`,\n agent.accessConfirmed ? '✓ access confirmed' : '✗ access not confirmed',\n ].join(' · ');\n\n const width = Math.max(\n 8,\n ...agent.requirements.map((item) => item.key.length),\n );\n const pad = (label: string) => label.padEnd(width);\n const indent = ' '.repeat(width + 4);\n\n const products = agent.requirements.flatMap((item) => {\n const fix = item.connected\n ? null\n : (requirementFix(item, target.team, target.source) ??\n `${CLI} teams mcp status ${target.team} ${item.key} --source ${target.source}`);\n const hidden =\n item.hiddenByScope && scope\n ? [\n `${indent}! ${scopeHiddenWords(scope)}`,\n `${indent}→ ${fixLine(scopeFix(scope, { ...target, product: item.key }))}`,\n ]\n : [];\n return [\n ` ${pad(item.key)} ${productState(item)}`,\n ...(fix ? [`${indent}→ ${fixLine(fix)}`] : []),\n ...hidden,\n ];\n });\n\n const nameWidth = Math.max(\n 0,\n ...agent.triggers.map(\n (trigger) => (trigger.eventId ?? trigger.type).length,\n ),\n );\n const triggers = agent.triggers.flatMap((trigger, index) => {\n const label = index === 0 ? pad('triggers') : pad('');\n const name = (trigger.eventId ?? trigger.type).padEnd(nameWidth);\n if (!trigger.enabled) return [` ${label} ${name} (off)`];\n const channel = (agent.channels ?? []).find((candidate) =>\n candidate.triggers.includes(trigger.eventId ?? trigger.type),\n );\n const reach = channel\n ? channel.ready\n ? `✓ reachable (${reachedVia(channel)}${channel.lastDeliveryAt ? `, last delivery ${channel.lastDeliveryAt}` : ''})`\n : `✗ ${channel.problem ?? `${channel.name} not ready`}`\n : `✓ ${TRIGGER_REACH[trigger.type] ?? 'reachable'}`;\n // An event trigger's runs are the ones its own events started; any\n // other trigger's, the agent's latest run of that trigger type.\n const ownEvents = trigger.eventId\n ? (activity.events ?? []).filter(\n (event) => event.eventId === trigger.eventId,\n )\n : [];\n const lastEvent = ownEvents[0];\n const lastRun = trigger.eventId\n ? ownEvents.find((event) => event.runs.length > 0)?.runs[0]\n : activity.runs?.find((run) => run.trigger === trigger.type);\n const known = trigger.eventId ? activity.events : activity.runs;\n const facts = [\n reach,\n ...(trigger.eventId && activity.events\n ? [\n lastEvent\n ? `last event ${lastEvent.receivedAt} ${lastEvent.status}`\n : 'no event yet',\n ]\n : []),\n ...(known\n ? [\n lastRun\n ? `last run ${lastRun.startedAt} ${lastRun.status}`\n : 'no run yet',\n ]\n : []),\n ];\n return [\n ` ${label} ${name} ${facts.join(' · ')}`,\n ...(channel && !channel.ready\n ? [\n `${indent}→ ${fixLine(channelFix(channel, target.team, target.source))}`,\n ]\n : []),\n ];\n });\n\n return [\n head,\n ...products,\n ...(agent.triggers.length > 0 ? triggers : [` ${pad('triggers')} none`]),\n ` ${liveLine(readiness)}`,\n ...(readiness.next ? [` Next: ${readiness.next}`] : []),\n ].join('\\n');\n}\n\nconst TRIGGER_REACH: Record<string, string> = {\n manual: 'started by hand',\n schedule: 'runs on its schedule',\n webhook: 'reachable at its trigger URL',\n};\n\nfunction productState(item: Requirement): string {\n if (item.kind === 'mcp') {\n return item.connected\n ? '✓ MCP server connected'\n : '✗ MCP server not signed in';\n }\n const via =\n item.via === 'source'\n ? 'via Source connection'\n : item.via === 'person'\n ? `via ${item.viaDetail ?? 'the runs-as person'}'s personal connection`\n : item.via === 'team'\n ? 'via team connection'\n : null;\n if (item.connected) {\n const routes =\n item.via === 'source' && item.viaDetail\n ? ` · routes: ${item.viaDetail}`\n : '';\n const fallback =\n item.reason && item.reason !== 'not_connected'\n ? ` (${REASON_WORDS[item.reason]})`\n : '';\n return `✓ ${via ?? 'connected'}${routes}${fallback}`;\n }\n const reason = REASON_WORDS[item.reason ?? 'not_connected'];\n return `✗ ${via ? `${via} — ` : ''}${reason}${item.required ? '' : ' (optional)'}`;\n}\n"]}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
|
+
import { type ChannelRequirement, type Requirement, type TeamAgentAccess } from '@ekanos/integration-schema';
|
|
1
2
|
import type { CliContext } from '../context.js';
|
|
2
3
|
import type { ExitCode } from '../exit-codes.js';
|
|
3
4
|
import { type TeamAgentRun } from './team-agents.js';
|
|
4
5
|
/**
|
|
5
|
-
* `ekanos teams agents list|enable|disable|pin|unpin|policy` —
|
|
6
|
-
* provided agents, turned on, versioned
|
|
7
|
-
* Source admin.
|
|
6
|
+
* `ekanos teams agents list|show|enable|confirm|disable|pin|unpin|policy|skills` —
|
|
7
|
+
* a team's provided agents, turned on, versioned, given an approval policy
|
|
8
|
+
* and skills by the Source admin. `enable|pin … --draft` puts one team on
|
|
9
|
+
* the template's latest, unpublished version to test it there before
|
|
10
|
+
* publishing. `confirm` (and `--confirm-access`) records the caller's own
|
|
11
|
+
* confirmation that it may use its connections in runs no one watches:
|
|
12
|
+
* whoever sets an agent up confirms it (plan 247.2), never a member.
|
|
13
|
+
* `show` answers "is this agent live, and if not, why?" for one agent; `list`
|
|
14
|
+
* ends each agent with the same verdict.
|
|
8
15
|
*/
|
|
9
16
|
export declare function runTeamAgentsArea(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;
|
|
17
|
+
/**
|
|
18
|
+
* What the agent still needs connected, each with why and the command that
|
|
19
|
+
* makes it; then any product working on another connection than the one its
|
|
20
|
+
* template names (the Source connection unusable, the team's own used).
|
|
21
|
+
*/
|
|
22
|
+
export declare function requirementLines(requirements: Requirement[], missing: Requirement[], team: string, source: string): string[];
|
|
23
|
+
/**
|
|
24
|
+
* What the agent's triggers need installed before they can fire: missing
|
|
25
|
+
* ones first, each with the command that installs it. A trigger listed above
|
|
26
|
+
* with its channel missing here is one that will never start a run.
|
|
27
|
+
*/
|
|
28
|
+
export declare function channelLines(channels: ChannelRequirement[], team: string, source: string): string[];
|
|
29
|
+
/** What a confirmation covers, in words: whose connections, to what. */
|
|
30
|
+
export declare function describeAccess(access: TeamAgentAccess): string;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, } from '@ekanos/integration-schema';
|
|
2
|
-
import { usageError } from '../errors.js';
|
|
3
|
-
import { call } from '../teams-api.js';
|
|
1
|
+
import { AgentRunListSchema, TeamAgentChangeResultSchema, TeamAgentListSchema, TeamAgentPolicySchema, TeamAgentSkillsSchema, } from '@ekanos/integration-schema';
|
|
2
|
+
import { invalidStateError, notFoundError, usageError } from '../errors.js';
|
|
3
|
+
import { call, listTeamEvents } from '../teams-api.js';
|
|
4
|
+
import { REASON_WORDS, agentReadiness, channelFix, describeAgentReadiness, fixLine, liveLine, reachedVia, requirementFix, } from './team-agent-readiness.js';
|
|
4
5
|
import { requireOperand, usageFor } from './team-agents.js';
|
|
5
6
|
/**
|
|
6
|
-
* `ekanos teams agents list|enable|disable|pin|unpin|policy` —
|
|
7
|
-
* provided agents, turned on, versioned
|
|
8
|
-
* Source admin.
|
|
7
|
+
* `ekanos teams agents list|show|enable|confirm|disable|pin|unpin|policy|skills` —
|
|
8
|
+
* 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
|
|
10
|
+
* the template's latest, unpublished version to test it there before
|
|
11
|
+
* publishing. `confirm` (and `--confirm-access`) records the caller's own
|
|
12
|
+
* confirmation that it may use its connections in runs no one watches:
|
|
13
|
+
* whoever sets an agent up confirms it (plan 247.2), never a member.
|
|
14
|
+
* `show` answers "is this agent live, and if not, why?" for one agent; `list`
|
|
15
|
+
* ends each agent with the same verdict.
|
|
9
16
|
*/
|
|
10
17
|
export async function runTeamAgentsArea(ctx, run) {
|
|
11
|
-
var _a;
|
|
18
|
+
var _a, _b, _c;
|
|
19
|
+
var _d, _e, _f;
|
|
12
20
|
const team = requireOperand(run.operands[0], 'team slug', 'agents');
|
|
13
21
|
const base = `/api/partner/teams/${encodeURIComponent(team)}/agents`;
|
|
14
22
|
if (run.verb === 'list') {
|
|
@@ -18,14 +26,15 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
18
26
|
path: base,
|
|
19
27
|
source: run.source,
|
|
20
28
|
}));
|
|
21
|
-
|
|
29
|
+
const target = { team: list.team.slug, source: run.source };
|
|
30
|
+
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) }))) }), [
|
|
22
31
|
ctx.ui.result({
|
|
23
32
|
title: list.agents.length === 0
|
|
24
33
|
? `No agents are provided for ${list.team.slug}`
|
|
25
34
|
: `Agents for ${list.team.slug}`,
|
|
26
35
|
tone: list.agents.length === 0 ? 'warn' : 'ok',
|
|
27
36
|
}),
|
|
28
|
-
...list.agents.map(describeEntry),
|
|
37
|
+
...list.agents.map((entry) => describeEntry(entry, list.team.slug, run.source)),
|
|
29
38
|
list.mcpServers.length > 0
|
|
30
39
|
? `\nMCP servers: ${list.mcpServers.map((server) => `${server.key} (${server.status})`).join(', ')}`
|
|
31
40
|
: '',
|
|
@@ -36,40 +45,128 @@ export async function runTeamAgentsArea(ctx, run) {
|
|
|
36
45
|
const key = requireOperand(run.operands[1], 'agent key', 'agents');
|
|
37
46
|
const path = `${base}/${encodeURIComponent(key)}`;
|
|
38
47
|
switch (run.verb) {
|
|
48
|
+
case 'show':
|
|
49
|
+
expectOperands(run, 2);
|
|
50
|
+
return show(ctx, run, base, key);
|
|
39
51
|
case 'enable': {
|
|
40
52
|
expectOperands(run, 2);
|
|
41
53
|
const as = stringFlag(run, 'as');
|
|
42
|
-
const
|
|
43
|
-
|
|
54
|
+
const draft = ((_a = run.args.flags) === null || _a === void 0 ? void 0 : _a.draft) === true;
|
|
55
|
+
const confirmAccess = ((_b = run.args.flags) === null || _b === void 0 ? void 0 : _b['confirm-access']) === true;
|
|
56
|
+
const result = await change(run, `${path}/enable`, 'POST', Object.assign(Object.assign(Object.assign({}, (as ? { as } : {})), (draft ? { draft: true } : {})), (confirmAccess ? { confirmAccess: true } : {})));
|
|
57
|
+
if (draft)
|
|
58
|
+
requireDraftHost(result, 'enabled');
|
|
59
|
+
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 what it may use' : ''}`, run.source, { confirmRequested: confirmAccess }));
|
|
62
|
+
}
|
|
63
|
+
case 'confirm': {
|
|
64
|
+
expectOperands(run, 2);
|
|
65
|
+
// Confirm what the person is shown, never a publish that lands after:
|
|
66
|
+
// the host refuses if the version moved (AGENT_VERSION_CHANGED).
|
|
67
|
+
const shown = await shownVersion(ctx, run, base, key);
|
|
68
|
+
const result = await change(run, `${path}/confirm`, 'POST', shown === null ? {} : { expectedVersion: shown });
|
|
69
|
+
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 }));
|
|
44
70
|
}
|
|
45
71
|
case 'disable': {
|
|
46
72
|
expectOperands(run, 2);
|
|
73
|
+
if (!run.args.yes) {
|
|
74
|
+
throw invalidStateError(`Turning ${key} off for ${team} pauses it: nothing starts it for that team until it is turned on again, and turning it on is refused once the person it runs as has left the team.`, `Re-run with --yes: ekanos teams agents disable ${team} ${key} --yes`);
|
|
75
|
+
}
|
|
47
76
|
const result = await change(run, `${path}/disable`, 'POST', {});
|
|
48
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned off ${result.slug} for ${result.team.slug}
|
|
77
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `Turned off ${result.slug} for ${result.team.slug}`, run.source));
|
|
49
78
|
}
|
|
50
79
|
case 'pin': {
|
|
80
|
+
if (((_c = run.args.flags) === null || _c === void 0 ? void 0 : _c.draft) === true) {
|
|
81
|
+
expectOperands(run, 2);
|
|
82
|
+
const result = await change(run, `${path}/pin`, 'PUT', {
|
|
83
|
+
version: null,
|
|
84
|
+
draft: true,
|
|
85
|
+
});
|
|
86
|
+
requireDraftHost(result, 'pinned');
|
|
87
|
+
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));
|
|
88
|
+
}
|
|
51
89
|
expectOperands(run, 3);
|
|
52
90
|
const version = Number(run.operands[2]);
|
|
53
91
|
if (!Number.isInteger(version) || version < 1) {
|
|
54
92
|
throw usageError(run.operands[2]
|
|
55
93
|
? `"${run.operands[2]}" is not a version number.`
|
|
56
|
-
: 'Name the version to pin.', `e.g. "ekanos teams agents pin ${team} ${key} 3". "ekanos agents show ${key}" lists its versions.`);
|
|
94
|
+
: '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.`);
|
|
57
95
|
}
|
|
58
96
|
const result = await change(run, `${path}/pin`, 'PUT', { version });
|
|
59
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} stays on v${(
|
|
97
|
+
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));
|
|
60
98
|
}
|
|
61
99
|
case 'unpin': {
|
|
62
100
|
expectOperands(run, 2);
|
|
63
101
|
const result = await change(run, `${path}/pin`, 'PUT', { version: null });
|
|
64
|
-
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}
|
|
102
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeChange(result, `${result.team.slug} follows each published version of ${result.slug}`, run.source));
|
|
65
103
|
}
|
|
66
104
|
case 'policy':
|
|
67
105
|
return policy(ctx, run, team, key, `${path}/policy`);
|
|
106
|
+
case 'skills':
|
|
107
|
+
return skills(ctx, run, team, key, `${path}/skills`);
|
|
68
108
|
default:
|
|
69
109
|
throw usageError(`Unknown teams agents subcommand "${run.verb}".`, usageFor('agents'));
|
|
70
110
|
}
|
|
71
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* One agent on one team: each product and whose connection it acts through,
|
|
114
|
+
* each trigger and how its events reach the agent (with the last event and
|
|
115
|
+
* the last run), access, "Live: yes/no" and exactly one Next. Reads the
|
|
116
|
+
* team's agents, then its recent runs and events; a host without the
|
|
117
|
+
* activity reads still answers the rest.
|
|
118
|
+
*/
|
|
119
|
+
async function show(ctx, run, base, key) {
|
|
120
|
+
var _a, _b, _c;
|
|
121
|
+
const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
|
|
122
|
+
method: 'GET',
|
|
123
|
+
path: base,
|
|
124
|
+
source: run.source,
|
|
125
|
+
}));
|
|
126
|
+
const entry = list.agents.find((candidate) => candidate.key === key);
|
|
127
|
+
if (!entry) {
|
|
128
|
+
throw notFoundError(`No agent "${key}" is provided for ${list.team.slug}.`, `"ekanos teams agents list ${list.team.slug}" lists the agents provided for it.`);
|
|
129
|
+
}
|
|
130
|
+
const target = { team: list.team.slug, source: run.source };
|
|
131
|
+
const readiness = agentReadiness(entry, target);
|
|
132
|
+
const [runs, events] = entry.agent
|
|
133
|
+
? await Promise.all([
|
|
134
|
+
activity(ctx, 'runs', () => run.client.call((token) => call(run.host, token, AgentRunListSchema, {
|
|
135
|
+
method: 'GET',
|
|
136
|
+
path: `/api/partner/teams/${encodeURIComponent(target.team)}/runs?agent=${encodeURIComponent(key)}`,
|
|
137
|
+
source: run.source,
|
|
138
|
+
}))),
|
|
139
|
+
entry.agent.triggers.some((trigger) => trigger.eventId)
|
|
140
|
+
? activity(ctx, 'events', () => run.client.call((token) => listTeamEvents(run.host, token, { source: run.source, team: target.team }, { limit: 100 })))
|
|
141
|
+
: Promise.resolve(null),
|
|
142
|
+
])
|
|
143
|
+
: [null, null];
|
|
144
|
+
return ctx.succeed({
|
|
145
|
+
host: run.host,
|
|
146
|
+
team: list.team,
|
|
147
|
+
agent: entry,
|
|
148
|
+
readiness,
|
|
149
|
+
lastRun: (_a = runs === null || runs === void 0 ? void 0 : runs.runs[0]) !== null && _a !== void 0 ? _a : null,
|
|
150
|
+
recentEvents: events
|
|
151
|
+
? events.events.filter((event) => { var _a; return (_a = entry.agent) === null || _a === void 0 ? void 0 : _a.triggers.some((trigger) => trigger.eventId === event.eventId); })
|
|
152
|
+
: null,
|
|
153
|
+
}, describeAgentReadiness(entry, target, readiness, {
|
|
154
|
+
runs: (_b = runs === null || runs === void 0 ? void 0 : runs.runs) !== null && _b !== void 0 ? _b : null,
|
|
155
|
+
events: (_c = events === null || events === void 0 ? void 0 : events.events) !== null && _c !== void 0 ? _c : null,
|
|
156
|
+
}, list.scope));
|
|
157
|
+
}
|
|
158
|
+
/** A read `show` can do without: on failure, say so and carry on. */
|
|
159
|
+
async function activity(ctx, what, read) {
|
|
160
|
+
try {
|
|
161
|
+
return await read();
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
ctx.log(`Could not read the team's recent ${what}: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
72
168
|
async function policy(ctx, run, team, key, path) {
|
|
169
|
+
var _a;
|
|
73
170
|
const [action, tool, decision] = run.operands.slice(2);
|
|
74
171
|
const change = {};
|
|
75
172
|
const reads = approvalFlag(run, 'reads');
|
|
@@ -95,21 +192,86 @@ async function policy(ctx, run, team, key, path) {
|
|
|
95
192
|
throw usageError(`Unknown policy action "${action}".`, usageFor('agents'));
|
|
96
193
|
}
|
|
97
194
|
const writing = Object.keys(change).length > 0;
|
|
98
|
-
const
|
|
99
|
-
|
|
195
|
+
const confirmAccess = ((_a = run.args.flags) === null || _a === void 0 ? void 0 : _a['confirm-access']) === true;
|
|
196
|
+
if (confirmAccess && !writing) {
|
|
197
|
+
throw usageError('--confirm-access goes with a policy change.', `To confirm on its own: "ekanos teams agents confirm ${team} ${key}".`);
|
|
198
|
+
}
|
|
199
|
+
const result = await run.client.call((token) => call(run.host, token, TeamAgentPolicySchema, Object.assign({ method: writing ? 'PUT' : 'GET', path, source: run.source }, (writing
|
|
200
|
+
? { body: Object.assign(Object.assign({}, change), (confirmAccess ? { confirmAccess } : {})) }
|
|
201
|
+
: {}))));
|
|
202
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describePolicy(ctx, result, writing, run.source));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* `teams agents skills <team> <key> [add|remove <skill>]` — the skills the
|
|
206
|
+
* team's agent reads. A provided agent takes the team's own only where its
|
|
207
|
+
* template allows (`teamCustomization.skills`); its template's stay.
|
|
208
|
+
*/
|
|
209
|
+
async function skills(ctx, run, team, key, path) {
|
|
210
|
+
const [action, slug, extra] = run.operands.slice(2);
|
|
211
|
+
if (extra !== undefined) {
|
|
212
|
+
throw usageError(`Unexpected argument "${extra}".`, usageFor('agents'));
|
|
213
|
+
}
|
|
214
|
+
let change = null;
|
|
215
|
+
if (action === 'add' || action === 'remove') {
|
|
216
|
+
if (!slug) {
|
|
217
|
+
throw usageError(`skills ${action} needs a skill slug.`, `e.g. "ekanos teams agents skills ${team} ${key} ${action} refund-policy". "ekanos skills list --team ${team}" lists the team's skills.`);
|
|
218
|
+
}
|
|
219
|
+
change = { [action]: [slug.trim().toLowerCase()] };
|
|
220
|
+
}
|
|
221
|
+
else if (action !== undefined) {
|
|
222
|
+
throw usageError(`Unknown skills action "${action}".`, usageFor('agents'));
|
|
223
|
+
}
|
|
224
|
+
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 } : {}))));
|
|
225
|
+
return ctx.succeed(Object.assign({ host: run.host }, result), describeSkills(ctx, result, change));
|
|
100
226
|
}
|
|
101
|
-
function
|
|
227
|
+
function describeSkills(ctx, result, change) {
|
|
228
|
+
const [verb, slug] = (change === null || change === void 0 ? void 0 : change.add)
|
|
229
|
+
? ['Attached', change.add[0]]
|
|
230
|
+
: (change === null || change === void 0 ? void 0 : change.remove)
|
|
231
|
+
? ['Detached', change.remove[0]]
|
|
232
|
+
: [null, null];
|
|
233
|
+
const head = ctx.ui.result({
|
|
234
|
+
title: verb
|
|
235
|
+
? `${verb} ${slug} ${verb === 'Attached' ? 'to' : 'from'} ${result.slug} on ${result.team.slug}`
|
|
236
|
+
: `Skills of ${result.slug} on ${result.team.slug}`,
|
|
237
|
+
tone: result.editable ? 'ok' : 'warn',
|
|
238
|
+
rows: [
|
|
239
|
+
[
|
|
240
|
+
'team skills',
|
|
241
|
+
result.editable ? 'allowed' : 'no — follows the template',
|
|
242
|
+
],
|
|
243
|
+
],
|
|
244
|
+
notes: result.lockedReason ? [result.lockedReason] : [],
|
|
245
|
+
});
|
|
246
|
+
if (result.skills.length === 0)
|
|
247
|
+
return `${head}\n\nNo skills attached.`;
|
|
248
|
+
return `${head}\n\n${ctx.ui.table(['skill', 'name', 'from'], result.skills.map((skill) => [
|
|
249
|
+
skill.slug,
|
|
250
|
+
skill.name,
|
|
251
|
+
skill.fromTemplate ? 'the template' : `${skill.level} skill`,
|
|
252
|
+
]))}`;
|
|
253
|
+
}
|
|
254
|
+
function describePolicy(ctx, policy, changed, source) {
|
|
255
|
+
// Absent from an older host: say nothing rather than guess.
|
|
256
|
+
const unconfirmed = policy.accessConfirmed === false;
|
|
102
257
|
const head = ctx.ui.result({
|
|
103
258
|
title: changed
|
|
104
259
|
? `Policy updated for ${policy.slug} on ${policy.team.slug}`
|
|
105
260
|
: `Policy of ${policy.slug} on ${policy.team.slug}`,
|
|
106
|
-
tone: policy.editable ? 'ok' : 'warn',
|
|
261
|
+
tone: policy.editable && !unconfirmed ? 'ok' : 'warn',
|
|
107
262
|
rows: [
|
|
108
263
|
['reads', policy.reads],
|
|
109
264
|
['writes', policy.writes],
|
|
110
265
|
['editable', policy.editable ? 'yes' : 'no — follows the template'],
|
|
111
266
|
],
|
|
112
|
-
notes:
|
|
267
|
+
notes: [
|
|
268
|
+
...(policy.lockedReason ? [policy.lockedReason] : []),
|
|
269
|
+
...(unconfirmed
|
|
270
|
+
? [
|
|
271
|
+
`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`,
|
|
272
|
+
]
|
|
273
|
+
: []),
|
|
274
|
+
],
|
|
113
275
|
});
|
|
114
276
|
if (policy.tools.length === 0) {
|
|
115
277
|
return `${head}\n\nNo tools yet: connect its integrations or MCP servers.`;
|
|
@@ -121,6 +283,24 @@ function describePolicy(ctx, policy, changed) {
|
|
|
121
283
|
`${tool.decision === 'auto' ? 'on its own' : 'waits for approval'}${tool.overridden ? ' (set per tool)' : ''}`,
|
|
122
284
|
]))}`;
|
|
123
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* The version `confirm` is about to approve — the one it runs — printed
|
|
288
|
+
* before it is sent, so the person confirms what they saw. Null when the
|
|
289
|
+
* team's agent has no version to name.
|
|
290
|
+
*/
|
|
291
|
+
async function shownVersion(ctx, run, base, key) {
|
|
292
|
+
var _a;
|
|
293
|
+
const list = await run.client.call((token) => call(run.host, token, TeamAgentListSchema, {
|
|
294
|
+
method: 'GET',
|
|
295
|
+
path: base,
|
|
296
|
+
source: run.source,
|
|
297
|
+
}));
|
|
298
|
+
const agent = (_a = list.agents.find((entry) => entry.key === key)) === null || _a === void 0 ? void 0 : _a.agent;
|
|
299
|
+
if (!agent || agent.version === null)
|
|
300
|
+
return null;
|
|
301
|
+
ctx.log(`Confirming what ${key} v${agent.version} on ${list.team.slug} may use${agent.runsAs ? ` (it runs as ${agent.runsAs})` : ''}.`);
|
|
302
|
+
return agent.version;
|
|
303
|
+
}
|
|
124
304
|
function change(run, path, method, body) {
|
|
125
305
|
return run.client.call((token) => call(run.host, token, TeamAgentChangeResultSchema, {
|
|
126
306
|
method,
|
|
@@ -129,38 +309,137 @@ function change(run, path, method, body) {
|
|
|
129
309
|
body,
|
|
130
310
|
}));
|
|
131
311
|
}
|
|
132
|
-
function describeEntry(entry) {
|
|
312
|
+
function describeEntry(entry, team, source) {
|
|
133
313
|
var _a, _b, _c;
|
|
314
|
+
const readiness = agentReadiness(entry, { team, source });
|
|
134
315
|
if (!entry.agent) {
|
|
135
|
-
return `\n${entry.key} — ${entry.name}\n off · v${(_a = entry.publishedVersion) !== null && _a !== void 0 ? _a : '?'} published ·
|
|
316
|
+
return `\n${entry.key} — ${entry.name}\n off · v${(_a = entry.publishedVersion) !== null && _a !== void 0 ? _a : '?'} published\n ${liveLine(readiness)} · Next: ${readiness.next}`;
|
|
136
317
|
}
|
|
137
318
|
const agent = entry.agent;
|
|
138
|
-
const version =
|
|
319
|
+
const version = versionLabel(agent);
|
|
139
320
|
const lines = [
|
|
140
321
|
`\n${entry.key} — ${entry.name}`,
|
|
141
|
-
` ${agent.status} · ${version} · runs as ${(
|
|
322
|
+
` ${agent.status} · ${version} · runs as ${(_b = agent.runsAs) !== null && _b !== void 0 ? _b : 'nobody'}${agent.accessConfirmed ? '' : ` · access not confirmed (${confirmCommand(team, entry.key, source)})`}`,
|
|
142
323
|
` triggers: ${agent.triggers.length === 0 ? 'none' : agent.triggers.map((trigger) => `${trigger.type}${trigger.enabled ? '' : ' (off)'}`).join(', ')}`,
|
|
143
324
|
` links: ${agent.links.length === 0 ? 'none' : agent.links.map((link) => `${link.kind}${link.mode ? `/${link.mode}` : ''} → ${link.to}`).join(', ')}`,
|
|
144
325
|
];
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
326
|
+
lines.push(...requirementLines(agent.requirements, agent.missing, team, source));
|
|
327
|
+
if (agent.draft)
|
|
328
|
+
lines.push(...draftLines(team, entry.key));
|
|
329
|
+
lines.push(...channelLines((_c = agent.channels) !== null && _c !== void 0 ? _c : [], team, source));
|
|
330
|
+
lines.push(` ${liveLine(readiness)}${readiness.next ? ` · Next: ${readiness.next}` : ''}`);
|
|
148
331
|
return lines.join('\n');
|
|
149
332
|
}
|
|
150
|
-
function
|
|
151
|
-
var _a, _b
|
|
333
|
+
function versionLabel(agent) {
|
|
334
|
+
var _a, _b;
|
|
335
|
+
if (agent.draft)
|
|
336
|
+
return `draft v${(_a = agent.version) !== null && _a !== void 0 ? _a : '?'} (testing, unpublished)`;
|
|
337
|
+
return `v${(_b = agent.version) !== null && _b !== void 0 ? _b : '?'} ${agent.pinned ? '(pinned)' : '(following)'}`;
|
|
338
|
+
}
|
|
339
|
+
/** What testing a draft on a team means, and the next step. */
|
|
340
|
+
function draftLines(team, key) {
|
|
341
|
+
return [
|
|
342
|
+
' Only this team runs the draft, and only when started by hand: its triggers, schedules and hand-offs do not start it, and every write waits for approval.',
|
|
343
|
+
` Test it: ekanos agents test ${key} --team ${team} --prompt "…" --follow. Publishing (ekanos agents publish ${key}) puts this team back to following.`,
|
|
344
|
+
];
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* An older host ignores `draft` and would have turned on, or unpinned to,
|
|
348
|
+
* the published version instead. Say so rather than report a draft test
|
|
349
|
+
* that is not happening.
|
|
350
|
+
*/
|
|
351
|
+
function requireDraftHost(result, verb) {
|
|
352
|
+
var _a;
|
|
353
|
+
if (result.draft === true)
|
|
354
|
+
return;
|
|
355
|
+
throw invalidStateError(`This host does not support testing a draft on one team: it ${verb} ${result.slug} on v${(_a = result.version) !== null && _a !== void 0 ? _a : '?'} ${result.pinned ? '(pinned)' : '(following)'} instead.`, `Check with "ekanos teams agents list ${result.team.slug}", and test once the host is updated.`);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* What the agent still needs connected, each with why and the command that
|
|
359
|
+
* makes it; then any product working on another connection than the one its
|
|
360
|
+
* template names (the Source connection unusable, the team's own used).
|
|
361
|
+
*/
|
|
362
|
+
export function requirementLines(requirements, missing, team, source) {
|
|
363
|
+
const missingLines = missing.flatMap((item) => {
|
|
364
|
+
const fix = requirementFix(item, team, source);
|
|
365
|
+
return [
|
|
366
|
+
` ✗ missing: ${item.name} (${item.kind === 'mcp' ? 'MCP server' : 'integration'} ${item.key})${item.reason && item.reason !== 'not_connected' ? ` — ${REASON_WORDS[item.reason]}` : ''}`,
|
|
367
|
+
...(fix ? [` → ${fix}`] : []),
|
|
368
|
+
];
|
|
369
|
+
});
|
|
370
|
+
const fallbacks = requirements
|
|
371
|
+
.filter((item) => item.connected &&
|
|
372
|
+
item.reason !== undefined &&
|
|
373
|
+
item.reason !== null &&
|
|
374
|
+
item.reason !== 'not_connected')
|
|
375
|
+
.flatMap((item) => {
|
|
376
|
+
const fix = requirementFix(item, team, source);
|
|
377
|
+
return [
|
|
378
|
+
` ! ${item.name} uses the team's own connection: ${REASON_WORDS[item.reason]}`,
|
|
379
|
+
...(fix ? [` → ${fix}`] : []),
|
|
380
|
+
];
|
|
381
|
+
});
|
|
382
|
+
return [...missingLines, ...fallbacks];
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* What the agent's triggers need installed before they can fire: missing
|
|
386
|
+
* ones first, each with the command that installs it. A trigger listed above
|
|
387
|
+
* with its channel missing here is one that will never start a run.
|
|
388
|
+
*/
|
|
389
|
+
export function channelLines(channels, team, source) {
|
|
390
|
+
return channels.flatMap((channel) => { var _a; return channel.ready
|
|
391
|
+
? [
|
|
392
|
+
channel.arrival === undefined || channel.arrival === 'install'
|
|
393
|
+
? ` ✓ ${channel.name} installed — ${channel.triggers.join(', ')} can fire`
|
|
394
|
+
: ` ✓ ${channel.triggers.join(', ')} reachable (${reachedVia(channel)}${channel.lastDeliveryAt ? `, last delivery ${channel.lastDeliveryAt}` : ''}) — can fire`,
|
|
395
|
+
]
|
|
396
|
+
: [
|
|
397
|
+
` ✗ missing: ${(_a = channel.problem) !== null && _a !== void 0 ? _a : `${channel.name} not ready`} — ${channel.triggers.join(', ')} can never fire until it is`,
|
|
398
|
+
` → ${fixLine(channelFix(channel, team, source))}`,
|
|
399
|
+
]; });
|
|
400
|
+
}
|
|
401
|
+
function describeChange(result, title, source, options = {}) {
|
|
402
|
+
var _a, _b;
|
|
403
|
+
const covers = result.access ? describeAccess(result.access) : null;
|
|
152
404
|
const lines = [
|
|
153
|
-
|
|
154
|
-
` ${result.status} ·
|
|
405
|
+
`${options.confirmRequested && !result.accessConfirmed ? '!' : '✓'} ${title}`,
|
|
406
|
+
` ${result.status} · ${versionLabel(result)} · runs as ${(_a = result.runsAs) !== null && _a !== void 0 ? _a : 'nobody'}`,
|
|
155
407
|
];
|
|
156
|
-
if (
|
|
157
|
-
|
|
408
|
+
if (result.accessConfirmed) {
|
|
409
|
+
if (covers) {
|
|
410
|
+
lines.push(` Confirmed: in runs no one watches it may use ${result.runsAs ? `${result.runsAs}'s` : 'their'} connections to ${covers}.`);
|
|
411
|
+
}
|
|
158
412
|
}
|
|
159
|
-
|
|
160
|
-
|
|
413
|
+
else {
|
|
414
|
+
if (options.confirmRequested) {
|
|
415
|
+
// An older host ignores confirmAccess rather than refusing it.
|
|
416
|
+
lines.push(' This host did not record the confirmation: it may not support confirming from the CLI yet.');
|
|
417
|
+
}
|
|
418
|
+
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)}`);
|
|
161
419
|
}
|
|
420
|
+
lines.push(...requirementLines([], result.missing, result.team.slug, source));
|
|
421
|
+
if (result.draft)
|
|
422
|
+
lines.push(...draftLines(result.team.slug, result.key));
|
|
423
|
+
lines.push(...channelLines((_b = result.channels) !== null && _b !== void 0 ? _b : [], result.team.slug, source));
|
|
162
424
|
return lines.join('\n');
|
|
163
425
|
}
|
|
426
|
+
/** What a confirmation covers, in words: whose connections, to what. */
|
|
427
|
+
export function describeAccess(access) {
|
|
428
|
+
if (access.scope === 'all')
|
|
429
|
+
return 'every tool of every product they connect';
|
|
430
|
+
if (access.scope === 'read_only')
|
|
431
|
+
return 'read from every product they connect';
|
|
432
|
+
const parts = [
|
|
433
|
+
...access.products.map((product) => `${product.name} (every tool)`),
|
|
434
|
+
...access.tools,
|
|
435
|
+
];
|
|
436
|
+
return parts.length > 0
|
|
437
|
+
? parts.join(', ')
|
|
438
|
+
: 'nothing yet (no products granted)';
|
|
439
|
+
}
|
|
440
|
+
function confirmCommand(team, key, source) {
|
|
441
|
+
return `ekanos teams agents confirm ${team} ${key} --source ${source}`;
|
|
442
|
+
}
|
|
164
443
|
function expectOperands(run, count) {
|
|
165
444
|
const extra = run.operands[count];
|
|
166
445
|
if (extra !== undefined) {
|