@ekanos/cli 0.15.0 → 0.17.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 +103 -8
- 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/add.d.ts +2 -0
- package/dist/commands/add.js +118 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/agents.js +3 -2
- 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/audiences.d.ts +31 -0
- package/dist/commands/audiences.js +239 -0
- package/dist/commands/audiences.js.map +1 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.js +41 -0
- package/dist/commands/build.js.map +1 -0
- 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/check.d.ts +2 -0
- package/dist/commands/check.js +43 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/codegen.d.ts +2 -0
- package/dist/commands/codegen.js +49 -0
- package/dist/commands/codegen.js.map +1 -0
- package/dist/commands/contract.d.ts +52 -0
- package/dist/commands/contract.js +300 -0
- package/dist/commands/contract.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.js +186 -12
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/index-experience.d.ts +31 -0
- package/dist/commands/index-experience.js +21 -0
- package/dist/commands/index-experience.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +12 -0
- package/dist/commands/init.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/new.d.ts +2 -0
- package/dist/commands/new.js +39 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/publish.d.ts +59 -0
- package/dist/commands/publish.js +118 -65
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/runs.d.ts +7 -3
- package/dist/commands/runs.js +21 -5
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +13 -0
- package/dist/commands/scope-notice.js +12 -4
- 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 +8 -1
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.js +150 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/team-agent-readiness.d.ts +18 -2
- package/dist/commands/team-agent-readiness.js +39 -39
- package/dist/commands/team-agent-readiness.js.map +1 -1
- package/dist/commands/team-agents-agents.d.ts +5 -2
- package/dist/commands/team-agents-agents.js +152 -15
- 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-audience.d.ts +12 -0
- package/dist/commands/teams-audience.js +144 -0
- package/dist/commands/teams-audience.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 +6 -2
- package/dist/commands/teams-overview.js.map +1 -1
- package/dist/commands/teams-scope.js +4 -0
- package/dist/commands/teams-scope.js.map +1 -1
- package/dist/commands/teams.d.ts +25 -5
- package/dist/commands/teams.js +106 -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/compatibility.d.ts +10 -1
- package/dist/compatibility.js +10 -1
- package/dist/compatibility.js.map +1 -1
- 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/dev-experience.d.ts +125 -0
- package/dist/dev-experience.js +128 -0
- package/dist/dev-experience.js.map +1 -0
- package/dist/experience/boundary.d.ts +12 -0
- package/dist/experience/boundary.js +260 -0
- package/dist/experience/boundary.js.map +1 -0
- package/dist/experience/build.d.ts +16 -0
- package/dist/experience/build.js +90 -0
- package/dist/experience/build.js.map +1 -0
- package/dist/experience/checks.d.ts +29 -0
- package/dist/experience/checks.js +133 -0
- package/dist/experience/checks.js.map +1 -0
- package/dist/experience/contract-sources.d.ts +36 -0
- package/dist/experience/contract-sources.js +111 -0
- package/dist/experience/contract-sources.js.map +1 -0
- package/dist/experience/definition-checks.d.ts +26 -0
- package/dist/experience/definition-checks.js +201 -0
- package/dist/experience/definition-checks.js.map +1 -0
- package/dist/experience/definition-shape.d.ts +60 -0
- package/dist/experience/definition-shape.js +2 -0
- package/dist/experience/definition-shape.js.map +1 -0
- package/dist/experience/init.d.ts +10 -0
- package/dist/experience/init.js +64 -0
- package/dist/experience/init.js.map +1 -0
- package/dist/experience/integrations-codegen.d.ts +17 -0
- package/dist/experience/integrations-codegen.js +51 -0
- package/dist/experience/integrations-codegen.js.map +1 -0
- package/dist/experience/json-schema-to-ts.d.ts +1 -0
- package/dist/experience/json-schema-to-ts.js +90 -0
- package/dist/experience/json-schema-to-ts.js.map +1 -0
- package/dist/experience/load-experience.d.ts +23 -0
- package/dist/experience/load-experience.js +115 -0
- package/dist/experience/load-experience.js.map +1 -0
- package/dist/experience/overrides.d.ts +8 -0
- package/dist/experience/overrides.js +21 -0
- package/dist/experience/overrides.js.map +1 -0
- package/dist/experience/pin-integration.d.ts +8 -0
- package/dist/experience/pin-integration.js +17 -0
- package/dist/experience/pin-integration.js.map +1 -0
- package/dist/experience/pin-ops.d.ts +12 -0
- package/dist/experience/pin-ops.js +36 -0
- package/dist/experience/pin-ops.js.map +1 -0
- package/dist/experience/pins.d.ts +35 -0
- package/dist/experience/pins.js +91 -0
- package/dist/experience/pins.js.map +1 -0
- package/dist/experience/project.d.ts +52 -0
- package/dist/experience/project.js +149 -0
- package/dist/experience/project.js.map +1 -0
- package/dist/experience/publish.d.ts +51 -0
- package/dist/experience/publish.js +144 -0
- package/dist/experience/publish.js.map +1 -0
- package/dist/experience/regenerate.d.ts +10 -0
- package/dist/experience/regenerate.js +33 -0
- package/dist/experience/regenerate.js.map +1 -0
- package/dist/experience/report.d.ts +9 -0
- package/dist/experience/report.js +23 -0
- package/dist/experience/report.js.map +1 -0
- package/dist/harness-scaffold.d.ts +52 -18
- package/dist/harness-scaffold.js +189 -9
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +494 -127
- 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/project-checks.d.ts +12 -0
- package/dist/project-checks.js +46 -0
- package/dist/project-checks.js.map +1 -1
- package/dist/project.d.ts +14 -0
- package/dist/project.js +10 -0
- package/dist/project.js.map +1 -1
- package/dist/repo/publish.d.ts +42 -0
- package/dist/repo/publish.js +225 -0
- package/dist/repo/publish.js.map +1 -0
- package/dist/repo/scaffold.d.ts +30 -0
- package/dist/repo/scaffold.js +165 -0
- package/dist/repo/scaffold.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 +49 -1
- package/dist/teams-api.js +149 -27
- 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/validate-findings.js +2 -1
- package/dist/validate-findings.js.map +1 -1
- 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/ekanos.json.tmpl +1 -0
- package/templates/experience/AGENTS.md.tmpl +22 -0
- package/templates/experience/ekanos.json.tmpl +7 -0
- package/templates/experience/ekanos.lock.json.tmpl +4 -0
- package/templates/experience/eslint.config.mjs.tmpl +25 -0
- package/templates/experience/gitignore.tmpl +17 -0
- package/templates/experience/package.json.tmpl +41 -0
- package/templates/experience/src/.ekanos/integrations.d.ts.tmpl +3 -0
- package/templates/experience/src/experience.ts.tmpl +30 -0
- package/templates/experience/src/widgets/hello-widget.tsx.tmpl +40 -0
- package/templates/experience/tsconfig.json.tmpl +20 -0
- package/templates/harness/app/%5F%5Fekanos/api/[...path]/route.ts.tmpl +9 -0
- package/templates/harness/app/[slug]/activation/page.tsx.tmpl +1 -1
- package/templates/harness/app/[slug]/page.tsx.tmpl +1 -1
- package/templates/harness/app/[slug]/tile/page.tsx.tmpl +1 -1
- package/templates/harness/app/[slug]/triggers/page.tsx.tmpl +1 -1
- package/templates/harness/app/[slug]/widgets/[widgetId]/page.tsx.tmpl +1 -1
- package/templates/harness/app/[slug]/widgets/page.tsx.tmpl +1 -1
- package/templates/harness/app/experience/layout.tsx.tmpl +17 -0
- package/templates/harness/app/experience/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/pages/[id]/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/review-queue/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/runs/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/widgets/[id]/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/widgets/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/workflows/[id]/page.tsx.tmpl +1 -0
- package/templates/harness/app/experience/workflows/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/connect/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/events/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/health/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/operations/[kind]/[name]/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/operations/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/activation/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/layout.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/tile/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/triggers/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/widgets/[widgetId]/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/preview/widgets/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/[slug]/runs/page.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/layout.tsx.tmpl +1 -0
- package/templates/harness/app/integrations/page.tsx.tmpl +1 -0
- package/templates/harness/app/page.experience.tsx.tmpl +5 -0
- package/templates/harness/repo/app/%5F%5Fekanos/api/[...path]/route.ts.tmpl +11 -0
- package/templates/harness/repo/app/(repo)/connections/page.tsx.tmpl +1 -0
- package/templates/harness/repo/app/(repo)/layout.tsx.tmpl +1 -0
- package/templates/harness/repo/app/(repo)/page.tsx.tmpl +1 -0
- package/templates/harness/repo/app/experiences/[name]/connect/page.tsx.tmpl +1 -0
- package/templates/harness/repo/app/experiences/[name]/layout.tsx.tmpl +9 -0
- package/templates/harness/repo/app/experiences/page.tsx.tmpl +5 -0
- package/templates/harness/repo/app/harness-shell.tsx.tmpl +9 -0
- package/templates/harness/repo/app/integrations/[slug]/layout.tsx.tmpl +1 -0
- package/templates/harness/repo/app/integrations/page.tsx.tmpl +5 -0
- package/templates/harness/repo/app/repo-experiences.ts.tmpl +5 -0
- package/templates/harness/styles/globals.css.tmpl +15 -1
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +43 -10
- 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 +26 -2
- package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
- package/templates/skills/build-integration/references/widget-design.md +1 -1
- package/templates/skills/ekanos-platform/SKILL.md +66 -14
- package/templates/skills/polish-widgets/references/patterns.md +3 -3
package/dist/teams-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProductScopeListSchema, ProductScopeProductChangeSchema, TeamScopesSchema, TeamScopesSetResultSchema, TeamAppSetResultSchema, TeamCreateResultSchema, TeamDisconnectResultSchema, TeamMemberChangeResultSchema, TeamMemberInviteResultSchema, TeamMemberListSchema, TeamRenameResultSchema, TeamRolesSchema, TeamIntegrationStatusSchema, TeamIntegrationEventListSchema, TeamListSchema, TeamWebhookMintResultSchema, } from '@ekanos/integration-schema';
|
|
1
|
+
import { AudienceListResponseSchema, AudienceResponseSchema, MemberAudienceSchema, MemberAudienceSetResultSchema, TeamAudienceSchema, TeamAudienceSetResultSchema, ProductScopeListSchema, ProductScopeProductChangeSchema, TeamScopesSchema, TeamScopesSetResultSchema, TeamAppSetResultSchema, TeamCreateResultSchema, TeamDisconnectResultSchema, TeamMemberChangeResultSchema, TeamMemberAddResultSchema, TeamMemberInviteResultSchema, TeamMemberListSchema, TeamRenameResultSchema, TeamRolesSchema, TeamIntegrationStatusSchema, TeamIntegrationEventListSchema, TeamListSchema, TeamWebhookMintResultSchema, } from '@ekanos/integration-schema';
|
|
2
2
|
import { request } from './auth/ekanos-api.js';
|
|
3
3
|
import { authRequiredError, forbiddenError, invalidStateError, networkError, notFoundError, usageError, validationError, } from './errors.js';
|
|
4
4
|
export function listTeams(host, accessToken, source) {
|
|
@@ -33,7 +33,8 @@ export function mintTeamWebhook(host, accessToken, target, webhookId) {
|
|
|
33
33
|
export function disconnectTeamIntegration(host, accessToken, target) {
|
|
34
34
|
return call(host, accessToken, TeamDisconnectResultSchema, {
|
|
35
35
|
method: 'DELETE',
|
|
36
|
-
|
|
36
|
+
// `--mine`: the caller's own personal connection, never another's.
|
|
37
|
+
path: `${integrationPath(target)}${target.mine ? '/mine' : ''}`,
|
|
37
38
|
source: target.source,
|
|
38
39
|
});
|
|
39
40
|
}
|
|
@@ -68,6 +69,15 @@ export function inviteTeamMember(host, accessToken, target, body) {
|
|
|
68
69
|
body,
|
|
69
70
|
});
|
|
70
71
|
}
|
|
72
|
+
/** `teams members add`: a member now, no invitation email (`PUT`). */
|
|
73
|
+
export function addTeamMember(host, accessToken, target, body) {
|
|
74
|
+
return call(host, accessToken, TeamMemberAddResultSchema, {
|
|
75
|
+
method: 'PUT',
|
|
76
|
+
path: membersPath(target.team),
|
|
77
|
+
source: target.source,
|
|
78
|
+
body,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
71
81
|
export function setTeamMemberRole(host, accessToken, target, role) {
|
|
72
82
|
return call(host, accessToken, TeamMemberChangeResultSchema, {
|
|
73
83
|
method: 'PATCH',
|
|
@@ -112,6 +122,67 @@ export function setTeamScopes(host, accessToken, target, scopes) {
|
|
|
112
122
|
body: { scopes },
|
|
113
123
|
});
|
|
114
124
|
}
|
|
125
|
+
export function listAudiences(host, accessToken, source) {
|
|
126
|
+
return call(host, accessToken, AudienceListResponseSchema, {
|
|
127
|
+
method: 'GET',
|
|
128
|
+
path: '/api/partner/audiences',
|
|
129
|
+
source,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
export function showAudience(host, accessToken, target) {
|
|
133
|
+
return call(host, accessToken, AudienceResponseSchema, {
|
|
134
|
+
method: 'GET',
|
|
135
|
+
path: `/api/partner/audiences/${encodeURIComponent(target.audience)}`,
|
|
136
|
+
source: target.source,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
export function createAudience(host, accessToken, source, body) {
|
|
140
|
+
return call(host, accessToken, AudienceResponseSchema, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
path: '/api/partner/audiences',
|
|
143
|
+
source,
|
|
144
|
+
body,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function updateAudience(host, accessToken, target, body) {
|
|
148
|
+
return call(host, accessToken, AudienceResponseSchema, {
|
|
149
|
+
method: 'PATCH',
|
|
150
|
+
path: `/api/partner/audiences/${encodeURIComponent(target.audience)}`,
|
|
151
|
+
source: target.source,
|
|
152
|
+
body,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
export function showTeamAudience(host, accessToken, target) {
|
|
156
|
+
return call(host, accessToken, TeamAudienceSchema, {
|
|
157
|
+
method: 'GET',
|
|
158
|
+
path: `/api/partner/teams/${encodeURIComponent(target.team)}/audience`,
|
|
159
|
+
source: target.source,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export function setTeamAudience(host, accessToken, target, audienceId) {
|
|
163
|
+
return call(host, accessToken, TeamAudienceSetResultSchema, {
|
|
164
|
+
method: 'PUT',
|
|
165
|
+
path: `/api/partner/teams/${encodeURIComponent(target.team)}/audience`,
|
|
166
|
+
source: target.source,
|
|
167
|
+
body: { audienceId },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
export function showMemberAudience(host, accessToken, target) {
|
|
171
|
+
return call(host, accessToken, MemberAudienceSchema, {
|
|
172
|
+
method: 'GET',
|
|
173
|
+
path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}/audience`,
|
|
174
|
+
source: target.source,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/** `audienceId: null` clears the member's own audience. */
|
|
178
|
+
export function setMemberAudience(host, accessToken, target, audienceId) {
|
|
179
|
+
return call(host, accessToken, MemberAudienceSetResultSchema, {
|
|
180
|
+
method: 'PUT',
|
|
181
|
+
path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}/audience`,
|
|
182
|
+
source: target.source,
|
|
183
|
+
body: { audienceId },
|
|
184
|
+
});
|
|
185
|
+
}
|
|
115
186
|
export function listTeamRoles(host, accessToken, target) {
|
|
116
187
|
return call(host, accessToken, TeamRolesSchema, {
|
|
117
188
|
method: 'GET',
|
|
@@ -143,6 +214,7 @@ function integrationPath(target) {
|
|
|
143
214
|
}
|
|
144
215
|
/** One partner teams call; shared by the team-agent clients (`team-agents-api.ts`). */
|
|
145
216
|
export async function call(host, accessToken, schema, init) {
|
|
217
|
+
var _a, _b;
|
|
146
218
|
const response = await request(`${host}${init.path}${init.path.includes('?') ? '&' : '?'}${new URLSearchParams({ source: init.source })}`, {
|
|
147
219
|
method: init.method,
|
|
148
220
|
headers: Object.assign({ accept: 'application/json', authorization: `Bearer ${accessToken}` }, (init.body === undefined
|
|
@@ -165,10 +237,18 @@ export async function call(host, accessToken, schema, init) {
|
|
|
165
237
|
? "Only a Source admin manages its teams' integrations. Ask one to run it."
|
|
166
238
|
: code === 'CONFIRM_NOT_PERMITTED'
|
|
167
239
|
? "Only a Source admin of the team's Source, or someone who manages the team's agents, confirms what an agent may use."
|
|
168
|
-
:
|
|
240
|
+
: code === 'PERSONAL_AGENT_CREATOR_ONLY'
|
|
241
|
+
? 'A personal agent acts with its creator\'s own connections, so only they change it, run it, decide its approvals or cancel its runs. "ekanos teams agents list <team>" shows whose each agent is.'
|
|
242
|
+
: code === 'NOT_A_TEAM_MEMBER'
|
|
243
|
+
? 'Add yourself to the team first ("ekanos teams members add <team> --self"), then run this again.'
|
|
244
|
+
: code === 'AGENTS_MANAGE_REQUIRED'
|
|
245
|
+
? 'Take a role on the team that holds agents.manage ("ekanos teams roles list <team>"), or make it your own agent with --personal.'
|
|
246
|
+
: code === 'PERSONAL_AGENT_CHANNEL_TRIGGER'
|
|
247
|
+
? 'Add a schedule or a webhook trigger instead: "ekanos teams triggers add <team> <key> schedule|webhook --prompt ...".'
|
|
248
|
+
: 'Run "ekanos sources" to list the sources you hold a seat on.');
|
|
169
249
|
}
|
|
170
250
|
if (response.status === 404) {
|
|
171
|
-
throw notFoundError(message !== null && message !== void 0 ? message : 'Not found.', code === 'TEAM_NOT_FOUND'
|
|
251
|
+
throw notFoundError(message !== null && message !== void 0 ? message : 'Not found.', (_a = (code ? LIFECYCLE_HINTS[code] : undefined)) !== null && _a !== void 0 ? _a : (code === 'TEAM_NOT_FOUND'
|
|
172
252
|
? 'Run "ekanos teams list" to see the teams on this Source.'
|
|
173
253
|
: code === 'PRODUCT_NOT_ENTITLED'
|
|
174
254
|
? '"ekanos sources products" shows what this Source has; only a super-admin enables a product for a Source (in /admin).'
|
|
@@ -178,37 +258,56 @@ export async function call(host, accessToken, schema, init) {
|
|
|
178
258
|
? 'Run "ekanos teams show <team> <product>" to see its team apps and webhooks.'
|
|
179
259
|
: code === 'MEMBER_NOT_FOUND'
|
|
180
260
|
? 'Run "ekanos teams members list <team>" to see its members and invitations.'
|
|
181
|
-
: code === '
|
|
182
|
-
? '
|
|
183
|
-
:
|
|
184
|
-
? 'Run "ekanos
|
|
185
|
-
:
|
|
186
|
-
|
|
187
|
-
|
|
261
|
+
: code === 'NOT_A_SOURCE_USER'
|
|
262
|
+
? 'Invite them instead, by email: "ekanos teams members invite <team> <email> --role <role>".'
|
|
263
|
+
: code === 'SKILL_NOT_FOUND'
|
|
264
|
+
? 'Run "ekanos skills list --team <team>" (and "ekanos skills list") to see the skills this team can use.'
|
|
265
|
+
: (code === null || code === void 0 ? void 0 : code.startsWith('AGENT_')) ||
|
|
266
|
+
code === 'TEMPLATE_NOT_FOUND'
|
|
267
|
+
? 'Run "ekanos teams agents list <team>" to see the team\'s agents.'
|
|
268
|
+
: /^(TRIGGER|LINK|MCP)_/.test(code !== null && code !== void 0 ? code : '')
|
|
269
|
+
? 'List them first: "ekanos teams triggers|links|mcp list <team> ..."'
|
|
270
|
+
: 'Run "ekanos sources" to list the sources you hold a seat on.'));
|
|
188
271
|
}
|
|
189
272
|
if (response.status === 409 && code === 'NO_TEAM_APP') {
|
|
190
273
|
throw invalidStateError(message !== null && message !== void 0 ? message : 'This integration takes no team app.', 'Teams connect through the Source\'s app: "ekanos apps show <product>".');
|
|
191
274
|
}
|
|
192
275
|
if (response.status === 409 || response.status === 422) {
|
|
193
|
-
throw invalidStateError(message !== null && message !== void 0 ? message : 'The host refused the change.', code === 'SLUG_TAKEN'
|
|
276
|
+
throw invalidStateError(message !== null && message !== void 0 ? message : 'The host refused the change.', (_b = (code ? LIFECYCLE_HINTS[code] : undefined)) !== null && _b !== void 0 ? _b : (code === 'SLUG_TAKEN'
|
|
194
277
|
? 'Pick another with --slug, or run "ekanos teams list" to see the teams.'
|
|
195
278
|
: code === 'AGENT_VERSION_CHANGED'
|
|
196
279
|
? 'A newer version was published since it was shown to you. Review it with "ekanos teams agents show <team> <key>", then run "ekanos teams agents confirm" again.'
|
|
197
|
-
: code === '
|
|
198
|
-
? '
|
|
199
|
-
: code === '
|
|
200
|
-
? "
|
|
201
|
-
: code === '
|
|
202
|
-
? '
|
|
203
|
-
: code === '
|
|
204
|
-
? "The
|
|
205
|
-
: code === '
|
|
206
|
-
? '
|
|
207
|
-
: code === '
|
|
208
|
-
? '
|
|
209
|
-
: code === '
|
|
210
|
-
? '
|
|
211
|
-
:
|
|
280
|
+
: code === 'ROLE_NEEDS_ACCEPTANCE'
|
|
281
|
+
? 'Add them with a lower role (--role admin), or invite them to the top role so they accept it: "ekanos teams members invite <team> <email> --role owner".'
|
|
282
|
+
: code === 'AGENT_VERSION_CONFLICT'
|
|
283
|
+
? `Review it with "ekanos teams agents show <team> <key>", then apply with --base-version ${typeof body.latestVersion === 'number' ? body.latestVersion : '<its version>'} (or --overwrite to replace it anyway).`
|
|
284
|
+
: code === 'ALREADY_MEMBER' || code === 'ALREADY_INVITED'
|
|
285
|
+
? 'Run "ekanos teams members list <team>"; change a role with "ekanos teams members role <team> <email> <role>".'
|
|
286
|
+
: code === 'PRIMARY_OWNER'
|
|
287
|
+
? "The primary owner's ownership is transferred in the app (team Settings → Members)."
|
|
288
|
+
: code === 'TEAM_ACCOUNTS_DISABLED'
|
|
289
|
+
? 'Ekanos switches team accounts on for a Source; ask a super-admin.'
|
|
290
|
+
: code === 'PERSONAL_CONNECTION'
|
|
291
|
+
? 'Each member disconnects their own: "ekanos teams disconnect <team> <product> --mine".'
|
|
292
|
+
: code === 'MCP_SERVER_FROM_TEMPLATE'
|
|
293
|
+
? 'It stays while the agent template declares it: change the template, apply and publish.'
|
|
294
|
+
: code === 'PRODUCT_NOT_ENTITLED'
|
|
295
|
+
? '"ekanos sources products" shows what this Source has; only those can be in its scopes.'
|
|
296
|
+
: code === 'TEMPLATE_ARCHIVED'
|
|
297
|
+
? 'Unarchive it first: "ekanos agents unarchive <key>".'
|
|
298
|
+
: 'See "ekanos teams --help".'));
|
|
299
|
+
}
|
|
300
|
+
if (response.status === 400 && code === 'INVALID_AGENT') {
|
|
301
|
+
const issues = Array.isArray(body.issues)
|
|
302
|
+
? body.issues.flatMap((issue) => { var _a; return typeof issue === 'object' &&
|
|
303
|
+
issue !== null &&
|
|
304
|
+
typeof issue.message === 'string'
|
|
305
|
+
? [
|
|
306
|
+
` ${String((_a = issue.path) !== null && _a !== void 0 ? _a : '(root)')}: ${issue.message}`,
|
|
307
|
+
]
|
|
308
|
+
: []; })
|
|
309
|
+
: [];
|
|
310
|
+
throw validationError([message !== null && message !== void 0 ? message : 'The agent is not valid.', ...issues].join('\n'), 'Fix agent.json and run it again.');
|
|
212
311
|
}
|
|
213
312
|
if (response.status === 400 && code === 'UNKNOWN_ROLE') {
|
|
214
313
|
throw validationError(message !== null && message !== void 0 ? message : 'No such role.', 'Run "ekanos teams roles list <team>" for the roles this Source uses.');
|
|
@@ -216,9 +315,15 @@ export async function call(host, accessToken, schema, init) {
|
|
|
216
315
|
if (response.status === 400 && code === 'INVALID_FIELDS') {
|
|
217
316
|
throw validationError(message !== null && message !== void 0 ? message : 'The host refused the fields.', 'Run "ekanos teams app set <team> <product>" again.');
|
|
218
317
|
}
|
|
318
|
+
if (response.status === 400 && code === 'SECRET_AS_ARGUMENT') {
|
|
319
|
+
throw usageError(message !== null && message !== void 0 ? message : 'A secret was passed as an argument.', 'Leave that field out of --set: pass it with --set-secret <field>=env:<NAME>|file:<path>|stdin or --browser, or run the command at your terminal, which asks for it hidden.');
|
|
320
|
+
}
|
|
219
321
|
if (response.status === 400) {
|
|
220
322
|
throw usageError(message !== null && message !== void 0 ? message : 'The host refused the request.', 'See "ekanos teams --help".');
|
|
221
323
|
}
|
|
324
|
+
if (response.status >= 500 && code && message) {
|
|
325
|
+
throw networkError(message, 'The host could not finish it; retry shortly.');
|
|
326
|
+
}
|
|
222
327
|
if (!response.ok) {
|
|
223
328
|
throw networkError(`${host}${init.path} responded ${response.status}.`, response.status >= 500
|
|
224
329
|
? 'The Ekanos deployment returned a server error. Retry shortly.'
|
|
@@ -230,6 +335,23 @@ export async function call(host, accessToken, schema, init) {
|
|
|
230
335
|
}
|
|
231
336
|
return { status: 'ok', data: parsed.data };
|
|
232
337
|
}
|
|
338
|
+
/** Next steps for the refusals of the team lifecycle, roles and groups calls. */
|
|
339
|
+
const LIFECYCLE_HINTS = {
|
|
340
|
+
GROUP_NOT_FOUND: 'Run "ekanos teams groups list <team>" to see its groups (name one by name or id).',
|
|
341
|
+
GROUP_AMBIGUOUS: 'Run "ekanos teams groups list <team> --json" and name the group by its id.',
|
|
342
|
+
GROUP_EXISTS: 'Pick another name, or change that group: "ekanos teams groups update <team> <group> …".',
|
|
343
|
+
ROLE_NOT_FOUND: 'Run "ekanos sources roles list" to see the Source\'s roles.',
|
|
344
|
+
ROLE_EXISTS: 'Change it instead: "ekanos sources roles update <role> …", or pick another name.',
|
|
345
|
+
SYSTEM_ROLE: 'Owner, admin and member are fixed; create a custom role with "ekanos sources roles create <name> …".',
|
|
346
|
+
ROLE_IN_USE: 'Give its members another role first: "ekanos teams members role <team> <email> <role>"; "ekanos sources people" shows who holds what.',
|
|
347
|
+
WORKSPACE_NOT_FOUND: 'Run "ekanos teams workspace list <team>" to see its workspaces.',
|
|
348
|
+
WORKSPACES_DISABLED: 'Workspaces are a Source Flag (enable_workspaces) only a super-admin switches.',
|
|
349
|
+
NOT_A_MEMBER: 'Run "ekanos teams members list <team>" to see who is on it; you leave only a team you are a member of.',
|
|
350
|
+
NOT_CONNECTED: 'Connect it first: "ekanos teams connect <team> <product>"; "ekanos teams health <team>" lists what it has.',
|
|
351
|
+
USER_SCOPED: 'Each person connects it for themselves and checks it on their own Integrations → Health page.',
|
|
352
|
+
NO_HEALTH_CHECK: 'The product has no package on this deployment; "ekanos sources products" shows what is registered.',
|
|
353
|
+
PRODUCT_NOT_VISIBLE_TO_TEAM: 'Run "ekanos teams scope show <team>" for the products the team sees.',
|
|
354
|
+
};
|
|
233
355
|
async function readOptionalJson(response) {
|
|
234
356
|
try {
|
|
235
357
|
const parsed = await response.json();
|
package/dist/teams-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teams-api.js","sourceRoot":"","sources":["../src/teams-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ProductScopeList,\n ProductScopeListSchema,\n type ProductScopeProductChange,\n ProductScopeProductChangeSchema,\n type TeamScopes,\n TeamScopesSchema,\n type TeamScopesSetResult,\n TeamScopesSetResultSchema,\n type TeamAppSetResult,\n TeamAppSetResultSchema,\n type TeamCreateRequest,\n type TeamCreateResult,\n TeamCreateResultSchema,\n type TeamDisconnectResult,\n TeamDisconnectResultSchema,\n type TeamMemberChangeResult,\n TeamMemberChangeResultSchema,\n type TeamMemberInviteResult,\n TeamMemberInviteResultSchema,\n type TeamMemberList,\n TeamMemberListSchema,\n type TeamRenameResult,\n TeamRenameResultSchema,\n type TeamRoles,\n TeamRolesSchema,\n type TeamIntegrationStatus,\n TeamIntegrationStatusSchema,\n type TeamIntegrationEventList,\n TeamIntegrationEventListSchema,\n type TeamList,\n TeamListSchema,\n type TeamWebhookMintResult,\n TeamWebhookMintResultSchema,\n} from '@ekanos/integration-schema';\nimport type { z } from 'zod';\n\nimport { request } from './auth/ekanos-api';\nimport {\n authRequiredError,\n forbiddenError,\n invalidStateError,\n networkError,\n notFoundError,\n usageError,\n validationError,\n} from './errors';\n\n/**\n * The CLI's client for a Source's teams and their integration setup — the\n * team-level counterpart of `apps-api.ts`.\n *\n * GET /api/partner/teams?source=<slug> → TeamList\n * GET /api/partner/teams/<team>/integrations/<product>?source=<slug> → TeamIntegrationStatus\n * PUT …/integrations/<product>/app?source=<slug> { connectionId?, fields }\n * → TeamAppSetResult\n * POST …/integrations/<product>/webhooks/<id>?source=<slug> → TeamWebhookMintResult\n * DELETE /api/partner/teams/<team>/integrations/<product>?source=<slug> → TeamDisconnectResult\n * POST /api/partner/teams?source=<slug> { name, slug?, ownerEmail? } → TeamCreateResult\n * PATCH /api/partner/teams/<team>?source=<slug> { name } → TeamRenameResult\n * GET /api/partner/teams/<team>/members?source=<slug> → TeamMemberList\n * POST …/<team>/members?source=<slug> { email, role } → TeamMemberInviteResult\n * PATCH …/<team>/members/<email>?source=<slug> { role } → TeamMemberChangeResult\n * DELETE …/<team>/members/<email>?source=<slug> → TeamMemberChangeResult\n * GET /api/partner/teams/<team>/roles?source=<slug> → TeamRoles\n * GET /api/partner/teams/<team>/events?source=<slug>[&product=<slug>]\n * [&since=<iso>][&limit=<n>] → TeamIntegrationEventList\n * GET /api/partner/scopes?source=<slug> → ProductScopeList\n * PUT | DELETE /api/partner/scopes/<scope>/products/<product>?source=<slug>\n * → ProductScopeProductChange\n * GET /api/partner/teams/<team>/scopes?source=<slug> → TeamScopes\n * PUT /api/partner/teams/<team>/scopes?source=<slug> { scopes } → TeamScopesSetResult\n *\n * → 401 / 3xx refresh once and retry\n * → 403 { code: \"SOURCE_ADMIN_REQUIRED\" | \"MFA_REQUIRED\" | \"FORBIDDEN\" }\n * → 404 { code: \"TEAM_NOT_FOUND\" | \"PRODUCT_NOT_ENTITLED\" | \"WEBHOOK_NOT_FOUND\"\n * | \"CONNECTION_NOT_FOUND\" | \"SOURCE_NOT_FOUND\" }\n * | \"MEMBER_NOT_FOUND\" }\n * → 409 { code: \"NO_TEAM_APP\" | \"SLUG_TAKEN\" | \"TEAM_ACCOUNTS_DISABLED\"\n * | \"ALREADY_MEMBER\" | \"ALREADY_INVITED\" | \"PRIMARY_OWNER\" }\n * → 400 { code: \"INVALID_FIELDS\" | \"INVALID_REQUEST\" | \"UNKNOWN_ROLE\" }\n */\n\nexport type TeamsApiResult<T> =\n | { status: 'ok'; data: T }\n | { status: 'unauthorized' };\n\nexport function listTeams(\n host: string,\n accessToken: string,\n source: string,\n): Promise<TeamsApiResult<TeamList>> {\n return call(host, accessToken, TeamListSchema, {\n method: 'GET',\n path: '/api/partner/teams',\n source,\n });\n}\n\nexport function showTeamIntegration(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n): Promise<TeamsApiResult<TeamIntegrationStatus>> {\n return call(host, accessToken, TeamIntegrationStatusSchema, {\n method: 'GET',\n path: integrationPath(target),\n source: target.source,\n });\n}\n\nexport function setTeamApp(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n body: {\n connectionId?: string;\n fields: Record<string, string>;\n clear?: string[];\n },\n): Promise<TeamsApiResult<TeamAppSetResult>> {\n return call(host, accessToken, TeamAppSetResultSchema, {\n method: 'PUT',\n path: `${integrationPath(target)}/app`,\n source: target.source,\n body,\n });\n}\n\nexport function mintTeamWebhook(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n webhookId: string,\n): Promise<TeamsApiResult<TeamWebhookMintResult>> {\n return call(host, accessToken, TeamWebhookMintResultSchema, {\n method: 'POST',\n path: `${integrationPath(target)}/webhooks/${encodeURIComponent(webhookId)}`,\n source: target.source,\n });\n}\n\nexport function disconnectTeamIntegration(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n): Promise<TeamsApiResult<TeamDisconnectResult>> {\n return call(host, accessToken, TeamDisconnectResultSchema, {\n method: 'DELETE',\n path: integrationPath(target),\n source: target.source,\n });\n}\n\nexport function createTeam(\n host: string,\n accessToken: string,\n source: string,\n body: TeamCreateRequest,\n): Promise<TeamsApiResult<TeamCreateResult>> {\n return call(host, accessToken, TeamCreateResultSchema, {\n method: 'POST',\n path: '/api/partner/teams',\n source,\n body,\n });\n}\n\nexport function renameTeam(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n name: string,\n): Promise<TeamsApiResult<TeamRenameResult>> {\n return call(host, accessToken, TeamRenameResultSchema, {\n method: 'PATCH',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}`,\n source: target.source,\n body: { name },\n });\n}\n\nexport function listTeamMembers(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamMemberList>> {\n return call(host, accessToken, TeamMemberListSchema, {\n method: 'GET',\n path: membersPath(target.team),\n source: target.source,\n });\n}\n\nexport function inviteTeamMember(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n body: { email: string; role: string },\n): Promise<TeamsApiResult<TeamMemberInviteResult>> {\n return call(host, accessToken, TeamMemberInviteResultSchema, {\n method: 'POST',\n path: membersPath(target.team),\n source: target.source,\n body,\n });\n}\n\nexport function setTeamMemberRole(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n role: string,\n): Promise<TeamsApiResult<TeamMemberChangeResult>> {\n return call(host, accessToken, TeamMemberChangeResultSchema, {\n method: 'PATCH',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}`,\n source: target.source,\n body: { role },\n });\n}\n\nexport function removeTeamMember(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n): Promise<TeamsApiResult<TeamMemberChangeResult>> {\n return call(host, accessToken, TeamMemberChangeResultSchema, {\n method: 'DELETE',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}`,\n source: target.source,\n });\n}\n\nexport function listProductScopes(\n host: string,\n accessToken: string,\n source: string,\n): Promise<TeamsApiResult<ProductScopeList>> {\n return call(host, accessToken, ProductScopeListSchema, {\n method: 'GET',\n path: '/api/partner/scopes',\n source,\n });\n}\n\nexport function setScopeProduct(\n host: string,\n accessToken: string,\n target: { source: string; scope: string; product: string },\n included: boolean,\n): Promise<TeamsApiResult<ProductScopeProductChange>> {\n return call(host, accessToken, ProductScopeProductChangeSchema, {\n method: included ? 'PUT' : 'DELETE',\n path: `/api/partner/scopes/${encodeURIComponent(target.scope)}/products/${encodeURIComponent(target.product)}`,\n source: target.source,\n });\n}\n\nexport function showTeamScopes(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamScopes>> {\n return call(host, accessToken, TeamScopesSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/scopes`,\n source: target.source,\n });\n}\n\nexport function setTeamScopes(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n scopes: string[],\n): Promise<TeamsApiResult<TeamScopesSetResult>> {\n return call(host, accessToken, TeamScopesSetResultSchema, {\n method: 'PUT',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/scopes`,\n source: target.source,\n body: { scopes },\n });\n}\n\nexport function listTeamRoles(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamRoles>> {\n return call(host, accessToken, TeamRolesSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/roles`,\n source: target.source,\n });\n}\n\nexport function listTeamEvents(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n filters: { product?: string; since?: string; limit?: number },\n): Promise<TeamsApiResult<TeamIntegrationEventList>> {\n const query = new URLSearchParams();\n if (filters.product) query.set('product', filters.product);\n if (filters.since) query.set('since', filters.since);\n if (filters.limit !== undefined) query.set('limit', String(filters.limit));\n const encoded = query.toString();\n const suffix = encoded ? `?${encoded}` : '';\n return call(host, accessToken, TeamIntegrationEventListSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/events${suffix}`,\n source: target.source,\n });\n}\n\nfunction membersPath(team: string): string {\n return `/api/partner/teams/${encodeURIComponent(team)}/members`;\n}\n\nfunction integrationPath(target: { team: string; product: string }): string {\n return `/api/partner/teams/${encodeURIComponent(target.team)}/integrations/${encodeURIComponent(target.product)}`;\n}\n\n/** One partner teams call; shared by the team-agent clients (`team-agents-api.ts`). */\nexport async function call<T>(\n host: string,\n accessToken: string,\n schema: z.ZodType<T>,\n init: {\n method: 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE';\n path: string;\n source: string;\n body?: unknown;\n },\n): Promise<TeamsApiResult<T>> {\n const response = await request(\n `${host}${init.path}${init.path.includes('?') ? '&' : '?'}${new URLSearchParams({ source: init.source })}`,\n {\n method: init.method,\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n ...(init.body === undefined\n ? {}\n : { 'content-type': 'application/json' }),\n },\n body: init.body === undefined ? undefined : JSON.stringify(init.body),\n },\n );\n\n if (\n response.status === 401 ||\n (response.status >= 300 && response.status < 400)\n ) {\n return { status: 'unauthorized' };\n }\n\n const body = await readOptionalJson(response);\n const code = typeof body.code === 'string' ? body.code : null;\n const message =\n typeof body.error === 'string' && body.error ? body.error : null;\n\n if (response.status === 403 && code === 'MFA_REQUIRED') {\n throw authRequiredError(\n message ?? `${host} requires multi-factor authentication.`,\n 'Complete MFA in the browser, then run \"ekanos login\" again.',\n );\n }\n if (response.status === 403) {\n throw forbiddenError(\n message ?? 'Not permitted on this Source.',\n code === 'SOURCE_ADMIN_REQUIRED'\n ? \"Only a Source admin manages its teams' integrations. Ask one to run it.\"\n : code === 'CONFIRM_NOT_PERMITTED'\n ? \"Only a Source admin of the team's Source, or someone who manages the team's agents, confirms what an agent may use.\"\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 404) {\n throw notFoundError(\n message ?? 'Not found.',\n code === 'TEAM_NOT_FOUND'\n ? 'Run \"ekanos teams list\" to see the teams on this Source.'\n : code === 'PRODUCT_NOT_ENTITLED'\n ? '\"ekanos sources products\" shows what this Source has; only a super-admin enables a product for a Source (in /admin).'\n : code === 'SCOPE_NOT_FOUND' || code === 'PRODUCT_NOT_IN_SCOPE'\n ? 'Run \"ekanos sources scopes\" to see the Source\\'s product scopes and their products.'\n : code === 'WEBHOOK_NOT_FOUND' || code === 'CONNECTION_NOT_FOUND'\n ? 'Run \"ekanos teams show <team> <product>\" to see its team apps and webhooks.'\n : code === 'MEMBER_NOT_FOUND'\n ? 'Run \"ekanos teams members list <team>\" to see its members and invitations.'\n : code === 'SKILL_NOT_FOUND'\n ? 'Run \"ekanos skills list --team <team>\" (and \"ekanos skills list\") to see the skills this team can use.'\n : code?.startsWith('AGENT_') || code === 'TEMPLATE_NOT_FOUND'\n ? 'Run \"ekanos teams agents list <team>\" to see the team\\'s agents.'\n : /^(TRIGGER|LINK|MCP)_/.test(code ?? '')\n ? 'List them first: \"ekanos teams triggers|links|mcp list <team> ...\"'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 409 && code === 'NO_TEAM_APP') {\n throw invalidStateError(\n message ?? 'This integration takes no team app.',\n 'Teams connect through the Source\\'s app: \"ekanos apps show <product>\".',\n );\n }\n if (response.status === 409 || response.status === 422) {\n throw invalidStateError(\n message ?? 'The host refused the change.',\n code === 'SLUG_TAKEN'\n ? 'Pick another with --slug, or run \"ekanos teams list\" to see the teams.'\n : code === 'AGENT_VERSION_CHANGED'\n ? 'A newer version was published since it was shown to you. Review it with \"ekanos teams agents show <team> <key>\", then run \"ekanos teams agents confirm\" again.'\n : code === 'ALREADY_MEMBER' || code === 'ALREADY_INVITED'\n ? 'Run \"ekanos teams members list <team>\"; change a role with \"ekanos teams members role <team> <email> <role>\".'\n : code === 'PRIMARY_OWNER'\n ? \"The primary owner's ownership is transferred in the app (team Settings → Members).\"\n : code === 'TEAM_ACCOUNTS_DISABLED'\n ? 'Ekanos switches team accounts on for a Source; ask a super-admin.'\n : code === 'PERSONAL_CONNECTION'\n ? \"The member who made it disconnects it on the team's Integrations page in the app.\"\n : code === 'MCP_SERVER_FROM_TEMPLATE'\n ? 'It stays while the agent template declares it: change the template, apply and publish.'\n : code === 'PRODUCT_NOT_ENTITLED'\n ? '\"ekanos sources products\" shows what this Source has; only those can be in its scopes.'\n : code === 'TEMPLATE_ARCHIVED'\n ? 'Unarchive it first: \"ekanos agents unarchive <key>\".'\n : 'See \"ekanos teams --help\".',\n );\n }\n if (response.status === 400 && code === 'UNKNOWN_ROLE') {\n throw validationError(\n message ?? 'No such role.',\n 'Run \"ekanos teams roles list <team>\" for the roles this Source uses.',\n );\n }\n if (response.status === 400 && code === 'INVALID_FIELDS') {\n throw validationError(\n message ?? 'The host refused the fields.',\n 'Run \"ekanos teams app set <team> <product>\" again.',\n );\n }\n if (response.status === 400) {\n throw usageError(\n message ?? 'The host refused the request.',\n 'See \"ekanos teams --help\".',\n );\n }\n if (!response.ok) {\n throw networkError(\n `${host}${init.path} responded ${response.status}.`,\n response.status >= 500\n ? 'The Ekanos deployment returned a server error. Retry shortly.'\n : 'Confirm the host runs a build that includes the teams routes.',\n );\n }\n\n const parsed = schema.safeParse(body.data);\n if (!parsed.success) {\n throw networkError(\n `${host}/api/partner/teams answered in a shape this CLI does not read.`,\n 'Run \"ekanos upgrade\" — the CLI and the host disagree on the teams contract.',\n );\n }\n return { status: 'ok', data: parsed.data };\n}\n\nasync function readOptionalJson(\n response: Response,\n): Promise<Record<string, unknown>> {\n try {\n const parsed: unknown = await response.json();\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"teams-api.js","sourceRoot":"","sources":["../src/teams-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AudienceCreateRequest,\n type AudienceListResponse,\n AudienceListResponseSchema,\n type AudienceResponse,\n AudienceResponseSchema,\n type AudienceUpdateRequest,\n type MemberAudience,\n MemberAudienceSchema,\n type MemberAudienceSetResult,\n MemberAudienceSetResultSchema,\n type TeamAudience,\n TeamAudienceSchema,\n type TeamAudienceSetResult,\n TeamAudienceSetResultSchema,\n type ProductScopeList,\n ProductScopeListSchema,\n type ProductScopeProductChange,\n ProductScopeProductChangeSchema,\n type TeamScopes,\n TeamScopesSchema,\n type TeamScopesSetResult,\n TeamScopesSetResultSchema,\n type TeamAppSetResult,\n TeamAppSetResultSchema,\n type TeamCreateRequest,\n type TeamCreateResult,\n TeamCreateResultSchema,\n type TeamDisconnectResult,\n TeamDisconnectResultSchema,\n type TeamMemberChangeResult,\n TeamMemberChangeResultSchema,\n type TeamMemberAddResult,\n TeamMemberAddResultSchema,\n type TeamMemberInviteResult,\n TeamMemberInviteResultSchema,\n type TeamMemberList,\n TeamMemberListSchema,\n type TeamRenameResult,\n TeamRenameResultSchema,\n type TeamRoles,\n TeamRolesSchema,\n type TeamIntegrationStatus,\n TeamIntegrationStatusSchema,\n type TeamIntegrationEventList,\n TeamIntegrationEventListSchema,\n type TeamList,\n TeamListSchema,\n type TeamWebhookMintResult,\n TeamWebhookMintResultSchema,\n} from '@ekanos/integration-schema';\nimport type { z } from 'zod';\n\nimport { request } from './auth/ekanos-api';\nimport {\n authRequiredError,\n forbiddenError,\n invalidStateError,\n networkError,\n notFoundError,\n usageError,\n validationError,\n} from './errors';\n\n/**\n * The CLI's client for a Source's teams and their integration setup — the\n * team-level counterpart of `apps-api.ts`.\n *\n * GET /api/partner/teams?source=<slug> → TeamList\n * GET /api/partner/teams/<team>/integrations/<product>?source=<slug> → TeamIntegrationStatus\n * PUT …/integrations/<product>/app?source=<slug> { connectionId?, fields }\n * → TeamAppSetResult\n * POST …/integrations/<product>/webhooks/<id>?source=<slug> → TeamWebhookMintResult\n * DELETE /api/partner/teams/<team>/integrations/<product>?source=<slug> → TeamDisconnectResult\n * POST /api/partner/teams?source=<slug> { name, slug?, ownerEmail? } → TeamCreateResult\n * PATCH /api/partner/teams/<team>?source=<slug> { name } → TeamRenameResult\n * GET /api/partner/teams/<team>/members?source=<slug> → TeamMemberList\n * POST …/<team>/members?source=<slug> { email, role } → TeamMemberInviteResult\n * PATCH …/<team>/members/<email>?source=<slug> { role } → TeamMemberChangeResult\n * DELETE …/<team>/members/<email>?source=<slug> → TeamMemberChangeResult\n * GET /api/partner/teams/<team>/roles?source=<slug> → TeamRoles\n * GET /api/partner/teams/<team>/events?source=<slug>[&product=<slug>]\n * [&since=<iso>][&limit=<n>] → TeamIntegrationEventList\n * GET /api/partner/scopes?source=<slug> → ProductScopeList\n * PUT | DELETE /api/partner/scopes/<scope>/products/<product>?source=<slug>\n * → ProductScopeProductChange\n * GET /api/partner/audiences?source=<slug> → AudienceListResponse\n * GET | PATCH /api/partner/audiences/<audience>?source=<slug> → AudienceResponse\n * POST /api/partner/audiences?source=<slug> { name, … } → AudienceResponse\n * GET | PUT /api/partner/teams/<team>/audience?source=<slug> { audienceId }\n * → TeamAudience | TeamAudienceSetResult\n * GET | PUT …/<team>/members/<email>/audience?source=<slug> { audienceId | null }\n * → MemberAudience | MemberAudienceSetResult\n * GET /api/partner/teams/<team>/scopes?source=<slug> → TeamScopes\n * PUT /api/partner/teams/<team>/scopes?source=<slug> { scopes } → TeamScopesSetResult\n *\n * → 401 / 3xx refresh once and retry\n * → 403 { code: \"SOURCE_ADMIN_REQUIRED\" | \"MFA_REQUIRED\" | \"FORBIDDEN\" }\n * → 404 { code: \"TEAM_NOT_FOUND\" | \"PRODUCT_NOT_ENTITLED\" | \"WEBHOOK_NOT_FOUND\"\n * | \"CONNECTION_NOT_FOUND\" | \"SOURCE_NOT_FOUND\" }\n * | \"MEMBER_NOT_FOUND\" }\n * → 409 { code: \"NO_TEAM_APP\" | \"SLUG_TAKEN\" | \"TEAM_ACCOUNTS_DISABLED\"\n * | \"ALREADY_MEMBER\" | \"ALREADY_INVITED\" | \"PRIMARY_OWNER\" }\n * → 400 { code: \"INVALID_FIELDS\" | \"INVALID_REQUEST\" | \"UNKNOWN_ROLE\" }\n */\n\nexport type TeamsApiResult<T> =\n | { status: 'ok'; data: T }\n | { status: 'unauthorized' };\n\nexport function listTeams(\n host: string,\n accessToken: string,\n source: string,\n): Promise<TeamsApiResult<TeamList>> {\n return call(host, accessToken, TeamListSchema, {\n method: 'GET',\n path: '/api/partner/teams',\n source,\n });\n}\n\nexport function showTeamIntegration(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n): Promise<TeamsApiResult<TeamIntegrationStatus>> {\n return call(host, accessToken, TeamIntegrationStatusSchema, {\n method: 'GET',\n path: integrationPath(target),\n source: target.source,\n });\n}\n\nexport function setTeamApp(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n body: {\n connectionId?: string;\n fields: Record<string, string>;\n clear?: string[];\n },\n): Promise<TeamsApiResult<TeamAppSetResult>> {\n return call(host, accessToken, TeamAppSetResultSchema, {\n method: 'PUT',\n path: `${integrationPath(target)}/app`,\n source: target.source,\n body,\n });\n}\n\nexport function mintTeamWebhook(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string },\n webhookId: string,\n): Promise<TeamsApiResult<TeamWebhookMintResult>> {\n return call(host, accessToken, TeamWebhookMintResultSchema, {\n method: 'POST',\n path: `${integrationPath(target)}/webhooks/${encodeURIComponent(webhookId)}`,\n source: target.source,\n });\n}\n\nexport function disconnectTeamIntegration(\n host: string,\n accessToken: string,\n target: { source: string; team: string; product: string; mine?: boolean },\n): Promise<TeamsApiResult<TeamDisconnectResult>> {\n return call(host, accessToken, TeamDisconnectResultSchema, {\n method: 'DELETE',\n // `--mine`: the caller's own personal connection, never another's.\n path: `${integrationPath(target)}${target.mine ? '/mine' : ''}`,\n source: target.source,\n });\n}\n\nexport function createTeam(\n host: string,\n accessToken: string,\n source: string,\n body: TeamCreateRequest,\n): Promise<TeamsApiResult<TeamCreateResult>> {\n return call(host, accessToken, TeamCreateResultSchema, {\n method: 'POST',\n path: '/api/partner/teams',\n source,\n body,\n });\n}\n\nexport function renameTeam(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n name: string,\n): Promise<TeamsApiResult<TeamRenameResult>> {\n return call(host, accessToken, TeamRenameResultSchema, {\n method: 'PATCH',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}`,\n source: target.source,\n body: { name },\n });\n}\n\nexport function listTeamMembers(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamMemberList>> {\n return call(host, accessToken, TeamMemberListSchema, {\n method: 'GET',\n path: membersPath(target.team),\n source: target.source,\n });\n}\n\nexport function inviteTeamMember(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n body: { email: string; role: string },\n): Promise<TeamsApiResult<TeamMemberInviteResult>> {\n return call(host, accessToken, TeamMemberInviteResultSchema, {\n method: 'POST',\n path: membersPath(target.team),\n source: target.source,\n body,\n });\n}\n\n/** `teams members add`: a member now, no invitation email (`PUT`). */\nexport function addTeamMember(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n body: { self: true; role?: string } | { email: string; role?: string },\n): Promise<TeamsApiResult<TeamMemberAddResult>> {\n return call(host, accessToken, TeamMemberAddResultSchema, {\n method: 'PUT',\n path: membersPath(target.team),\n source: target.source,\n body,\n });\n}\n\nexport function setTeamMemberRole(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n role: string,\n): Promise<TeamsApiResult<TeamMemberChangeResult>> {\n return call(host, accessToken, TeamMemberChangeResultSchema, {\n method: 'PATCH',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}`,\n source: target.source,\n body: { role },\n });\n}\n\nexport function removeTeamMember(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n): Promise<TeamsApiResult<TeamMemberChangeResult>> {\n return call(host, accessToken, TeamMemberChangeResultSchema, {\n method: 'DELETE',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}`,\n source: target.source,\n });\n}\n\nexport function listProductScopes(\n host: string,\n accessToken: string,\n source: string,\n): Promise<TeamsApiResult<ProductScopeList>> {\n return call(host, accessToken, ProductScopeListSchema, {\n method: 'GET',\n path: '/api/partner/scopes',\n source,\n });\n}\n\nexport function setScopeProduct(\n host: string,\n accessToken: string,\n target: { source: string; scope: string; product: string },\n included: boolean,\n): Promise<TeamsApiResult<ProductScopeProductChange>> {\n return call(host, accessToken, ProductScopeProductChangeSchema, {\n method: included ? 'PUT' : 'DELETE',\n path: `/api/partner/scopes/${encodeURIComponent(target.scope)}/products/${encodeURIComponent(target.product)}`,\n source: target.source,\n });\n}\n\nexport function showTeamScopes(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamScopes>> {\n return call(host, accessToken, TeamScopesSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/scopes`,\n source: target.source,\n });\n}\n\nexport function setTeamScopes(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n scopes: string[],\n): Promise<TeamsApiResult<TeamScopesSetResult>> {\n return call(host, accessToken, TeamScopesSetResultSchema, {\n method: 'PUT',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/scopes`,\n source: target.source,\n body: { scopes },\n });\n}\n\nexport function listAudiences(\n host: string,\n accessToken: string,\n source: string,\n): Promise<TeamsApiResult<AudienceListResponse>> {\n return call(host, accessToken, AudienceListResponseSchema, {\n method: 'GET',\n path: '/api/partner/audiences',\n source,\n });\n}\n\nexport function showAudience(\n host: string,\n accessToken: string,\n target: { source: string; audience: string },\n): Promise<TeamsApiResult<AudienceResponse>> {\n return call(host, accessToken, AudienceResponseSchema, {\n method: 'GET',\n path: `/api/partner/audiences/${encodeURIComponent(target.audience)}`,\n source: target.source,\n });\n}\n\nexport function createAudience(\n host: string,\n accessToken: string,\n source: string,\n body: AudienceCreateRequest,\n): Promise<TeamsApiResult<AudienceResponse>> {\n return call(host, accessToken, AudienceResponseSchema, {\n method: 'POST',\n path: '/api/partner/audiences',\n source,\n body,\n });\n}\n\nexport function updateAudience(\n host: string,\n accessToken: string,\n target: { source: string; audience: string },\n body: AudienceUpdateRequest,\n): Promise<TeamsApiResult<AudienceResponse>> {\n return call(host, accessToken, AudienceResponseSchema, {\n method: 'PATCH',\n path: `/api/partner/audiences/${encodeURIComponent(target.audience)}`,\n source: target.source,\n body,\n });\n}\n\nexport function showTeamAudience(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamAudience>> {\n return call(host, accessToken, TeamAudienceSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/audience`,\n source: target.source,\n });\n}\n\nexport function setTeamAudience(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n audienceId: string,\n): Promise<TeamsApiResult<TeamAudienceSetResult>> {\n return call(host, accessToken, TeamAudienceSetResultSchema, {\n method: 'PUT',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/audience`,\n source: target.source,\n body: { audienceId },\n });\n}\n\nexport function showMemberAudience(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n): Promise<TeamsApiResult<MemberAudience>> {\n return call(host, accessToken, MemberAudienceSchema, {\n method: 'GET',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}/audience`,\n source: target.source,\n });\n}\n\n/** `audienceId: null` clears the member's own audience. */\nexport function setMemberAudience(\n host: string,\n accessToken: string,\n target: { source: string; team: string; email: string },\n audienceId: string | null,\n): Promise<TeamsApiResult<MemberAudienceSetResult>> {\n return call(host, accessToken, MemberAudienceSetResultSchema, {\n method: 'PUT',\n path: `${membersPath(target.team)}/${encodeURIComponent(target.email)}/audience`,\n source: target.source,\n body: { audienceId },\n });\n}\n\nexport function listTeamRoles(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n): Promise<TeamsApiResult<TeamRoles>> {\n return call(host, accessToken, TeamRolesSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/roles`,\n source: target.source,\n });\n}\n\nexport function listTeamEvents(\n host: string,\n accessToken: string,\n target: { source: string; team: string },\n filters: { product?: string; since?: string; limit?: number },\n): Promise<TeamsApiResult<TeamIntegrationEventList>> {\n const query = new URLSearchParams();\n if (filters.product) query.set('product', filters.product);\n if (filters.since) query.set('since', filters.since);\n if (filters.limit !== undefined) query.set('limit', String(filters.limit));\n const encoded = query.toString();\n const suffix = encoded ? `?${encoded}` : '';\n return call(host, accessToken, TeamIntegrationEventListSchema, {\n method: 'GET',\n path: `/api/partner/teams/${encodeURIComponent(target.team)}/events${suffix}`,\n source: target.source,\n });\n}\n\nfunction membersPath(team: string): string {\n return `/api/partner/teams/${encodeURIComponent(team)}/members`;\n}\n\nfunction integrationPath(target: { team: string; product: string }): string {\n return `/api/partner/teams/${encodeURIComponent(target.team)}/integrations/${encodeURIComponent(target.product)}`;\n}\n\n/** One partner teams call; shared by the team-agent clients (`team-agents-api.ts`). */\nexport async function call<T>(\n host: string,\n accessToken: string,\n schema: z.ZodType<T>,\n init: {\n method: 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE';\n path: string;\n source: string;\n body?: unknown;\n },\n): Promise<TeamsApiResult<T>> {\n const response = await request(\n `${host}${init.path}${init.path.includes('?') ? '&' : '?'}${new URLSearchParams({ source: init.source })}`,\n {\n method: init.method,\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n ...(init.body === undefined\n ? {}\n : { 'content-type': 'application/json' }),\n },\n body: init.body === undefined ? undefined : JSON.stringify(init.body),\n },\n );\n\n if (\n response.status === 401 ||\n (response.status >= 300 && response.status < 400)\n ) {\n return { status: 'unauthorized' };\n }\n\n const body = await readOptionalJson(response);\n const code = typeof body.code === 'string' ? body.code : null;\n const message =\n typeof body.error === 'string' && body.error ? body.error : null;\n\n if (response.status === 403 && code === 'MFA_REQUIRED') {\n throw authRequiredError(\n message ?? `${host} requires multi-factor authentication.`,\n 'Complete MFA in the browser, then run \"ekanos login\" again.',\n );\n }\n if (response.status === 403) {\n throw forbiddenError(\n message ?? 'Not permitted on this Source.',\n code === 'SOURCE_ADMIN_REQUIRED'\n ? \"Only a Source admin manages its teams' integrations. Ask one to run it.\"\n : code === 'CONFIRM_NOT_PERMITTED'\n ? \"Only a Source admin of the team's Source, or someone who manages the team's agents, confirms what an agent may use.\"\n : code === 'PERSONAL_AGENT_CREATOR_ONLY'\n ? 'A personal agent acts with its creator\\'s own connections, so only they change it, run it, decide its approvals or cancel its runs. \"ekanos teams agents list <team>\" shows whose each agent is.'\n : code === 'NOT_A_TEAM_MEMBER'\n ? 'Add yourself to the team first (\"ekanos teams members add <team> --self\"), then run this again.'\n : code === 'AGENTS_MANAGE_REQUIRED'\n ? 'Take a role on the team that holds agents.manage (\"ekanos teams roles list <team>\"), or make it your own agent with --personal.'\n : code === 'PERSONAL_AGENT_CHANNEL_TRIGGER'\n ? 'Add a schedule or a webhook trigger instead: \"ekanos teams triggers add <team> <key> schedule|webhook --prompt ...\".'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 404) {\n throw notFoundError(\n message ?? 'Not found.',\n (code ? LIFECYCLE_HINTS[code] : undefined) ??\n (code === 'TEAM_NOT_FOUND'\n ? 'Run \"ekanos teams list\" to see the teams on this Source.'\n : code === 'PRODUCT_NOT_ENTITLED'\n ? '\"ekanos sources products\" shows what this Source has; only a super-admin enables a product for a Source (in /admin).'\n : code === 'SCOPE_NOT_FOUND' || code === 'PRODUCT_NOT_IN_SCOPE'\n ? 'Run \"ekanos sources scopes\" to see the Source\\'s product scopes and their products.'\n : code === 'WEBHOOK_NOT_FOUND' || code === 'CONNECTION_NOT_FOUND'\n ? 'Run \"ekanos teams show <team> <product>\" to see its team apps and webhooks.'\n : code === 'MEMBER_NOT_FOUND'\n ? 'Run \"ekanos teams members list <team>\" to see its members and invitations.'\n : code === 'NOT_A_SOURCE_USER'\n ? 'Invite them instead, by email: \"ekanos teams members invite <team> <email> --role <role>\".'\n : code === 'SKILL_NOT_FOUND'\n ? 'Run \"ekanos skills list --team <team>\" (and \"ekanos skills list\") to see the skills this team can use.'\n : code?.startsWith('AGENT_') ||\n code === 'TEMPLATE_NOT_FOUND'\n ? 'Run \"ekanos teams agents list <team>\" to see the team\\'s agents.'\n : /^(TRIGGER|LINK|MCP)_/.test(code ?? '')\n ? 'List them first: \"ekanos teams triggers|links|mcp list <team> ...\"'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.'),\n );\n }\n if (response.status === 409 && code === 'NO_TEAM_APP') {\n throw invalidStateError(\n message ?? 'This integration takes no team app.',\n 'Teams connect through the Source\\'s app: \"ekanos apps show <product>\".',\n );\n }\n if (response.status === 409 || response.status === 422) {\n throw invalidStateError(\n message ?? 'The host refused the change.',\n (code ? LIFECYCLE_HINTS[code] : undefined) ??\n (code === 'SLUG_TAKEN'\n ? 'Pick another with --slug, or run \"ekanos teams list\" to see the teams.'\n : code === 'AGENT_VERSION_CHANGED'\n ? 'A newer version was published since it was shown to you. Review it with \"ekanos teams agents show <team> <key>\", then run \"ekanos teams agents confirm\" again.'\n : code === 'ROLE_NEEDS_ACCEPTANCE'\n ? 'Add them with a lower role (--role admin), or invite them to the top role so they accept it: \"ekanos teams members invite <team> <email> --role owner\".'\n : code === 'AGENT_VERSION_CONFLICT'\n ? `Review it with \"ekanos teams agents show <team> <key>\", then apply with --base-version ${typeof body.latestVersion === 'number' ? body.latestVersion : '<its version>'} (or --overwrite to replace it anyway).`\n : code === 'ALREADY_MEMBER' || code === 'ALREADY_INVITED'\n ? 'Run \"ekanos teams members list <team>\"; change a role with \"ekanos teams members role <team> <email> <role>\".'\n : code === 'PRIMARY_OWNER'\n ? \"The primary owner's ownership is transferred in the app (team Settings → Members).\"\n : code === 'TEAM_ACCOUNTS_DISABLED'\n ? 'Ekanos switches team accounts on for a Source; ask a super-admin.'\n : code === 'PERSONAL_CONNECTION'\n ? 'Each member disconnects their own: \"ekanos teams disconnect <team> <product> --mine\".'\n : code === 'MCP_SERVER_FROM_TEMPLATE'\n ? 'It stays while the agent template declares it: change the template, apply and publish.'\n : code === 'PRODUCT_NOT_ENTITLED'\n ? '\"ekanos sources products\" shows what this Source has; only those can be in its scopes.'\n : code === 'TEMPLATE_ARCHIVED'\n ? 'Unarchive it first: \"ekanos agents unarchive <key>\".'\n : 'See \"ekanos teams --help\".'),\n );\n }\n if (response.status === 400 && code === 'INVALID_AGENT') {\n const issues = Array.isArray(body.issues)\n ? body.issues.flatMap((issue: unknown) =>\n typeof issue === 'object' &&\n issue !== null &&\n typeof (issue as { message?: unknown }).message === 'string'\n ? [\n ` ${String((issue as { path?: unknown }).path ?? '(root)')}: ${(issue as { message: string }).message}`,\n ]\n : [],\n )\n : [];\n throw validationError(\n [message ?? 'The agent is not valid.', ...issues].join('\\n'),\n 'Fix agent.json and run it again.',\n );\n }\n if (response.status === 400 && code === 'UNKNOWN_ROLE') {\n throw validationError(\n message ?? 'No such role.',\n 'Run \"ekanos teams roles list <team>\" for the roles this Source uses.',\n );\n }\n if (response.status === 400 && code === 'INVALID_FIELDS') {\n throw validationError(\n message ?? 'The host refused the fields.',\n 'Run \"ekanos teams app set <team> <product>\" again.',\n );\n }\n if (response.status === 400 && code === 'SECRET_AS_ARGUMENT') {\n throw usageError(\n message ?? 'A secret was passed as an argument.',\n 'Leave that field out of --set: pass it with --set-secret <field>=env:<NAME>|file:<path>|stdin or --browser, or run the command at your terminal, which asks for it hidden.',\n );\n }\n if (response.status === 400) {\n throw usageError(\n message ?? 'The host refused the request.',\n 'See \"ekanos teams --help\".',\n );\n }\n if (response.status >= 500 && code && message) {\n throw networkError(message, 'The host could not finish it; retry shortly.');\n }\n if (!response.ok) {\n throw networkError(\n `${host}${init.path} responded ${response.status}.`,\n response.status >= 500\n ? 'The Ekanos deployment returned a server error. Retry shortly.'\n : 'Confirm the host runs a build that includes the teams routes.',\n );\n }\n\n const parsed = schema.safeParse(body.data);\n if (!parsed.success) {\n throw networkError(\n `${host}/api/partner/teams answered in a shape this CLI does not read.`,\n 'Run \"ekanos upgrade\" — the CLI and the host disagree on the teams contract.',\n );\n }\n return { status: 'ok', data: parsed.data };\n}\n\n/** Next steps for the refusals of the team lifecycle, roles and groups calls. */\nconst LIFECYCLE_HINTS: Record<string, string> = {\n GROUP_NOT_FOUND:\n 'Run \"ekanos teams groups list <team>\" to see its groups (name one by name or id).',\n GROUP_AMBIGUOUS:\n 'Run \"ekanos teams groups list <team> --json\" and name the group by its id.',\n GROUP_EXISTS:\n 'Pick another name, or change that group: \"ekanos teams groups update <team> <group> …\".',\n ROLE_NOT_FOUND: 'Run \"ekanos sources roles list\" to see the Source\\'s roles.',\n ROLE_EXISTS:\n 'Change it instead: \"ekanos sources roles update <role> …\", or pick another name.',\n SYSTEM_ROLE:\n 'Owner, admin and member are fixed; create a custom role with \"ekanos sources roles create <name> …\".',\n ROLE_IN_USE:\n 'Give its members another role first: \"ekanos teams members role <team> <email> <role>\"; \"ekanos sources people\" shows who holds what.',\n WORKSPACE_NOT_FOUND:\n 'Run \"ekanos teams workspace list <team>\" to see its workspaces.',\n WORKSPACES_DISABLED:\n 'Workspaces are a Source Flag (enable_workspaces) only a super-admin switches.',\n NOT_A_MEMBER:\n 'Run \"ekanos teams members list <team>\" to see who is on it; you leave only a team you are a member of.',\n NOT_CONNECTED:\n 'Connect it first: \"ekanos teams connect <team> <product>\"; \"ekanos teams health <team>\" lists what it has.',\n USER_SCOPED:\n 'Each person connects it for themselves and checks it on their own Integrations → Health page.',\n NO_HEALTH_CHECK:\n 'The product has no package on this deployment; \"ekanos sources products\" shows what is registered.',\n PRODUCT_NOT_VISIBLE_TO_TEAM:\n 'Run \"ekanos teams scope show <team>\" for the products the team sees.',\n};\n\nasync function readOptionalJson(\n response: Response,\n): Promise<Record<string, unknown>> {\n try {\n const parsed: unknown = await response.json();\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CliError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* The error for a first argument that is not a command, with the one fix
|
|
4
|
+
* most likely meant:
|
|
5
|
+
*
|
|
6
|
+
* - a whole command passed as ONE argument (`ekanos "teams list"`, which a
|
|
7
|
+
* shell or an agent's tool call produces when it quotes the line), whose
|
|
8
|
+
* first word is a command → the same words as separate arguments;
|
|
9
|
+
* - a typo of a command (`ekanos tems`) → the closest command;
|
|
10
|
+
* - otherwise the command list.
|
|
11
|
+
*
|
|
12
|
+
* `suggestion` is the corrected command line, or null when there is none to
|
|
13
|
+
* offer. It is also what the `claude-code-hint` line carries.
|
|
14
|
+
*/
|
|
15
|
+
export declare function unknownCommand(given: string, rest: readonly string[], commands: readonly string[]): {
|
|
16
|
+
error: CliError;
|
|
17
|
+
suggestion: string | null;
|
|
18
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { suggestKey } from './did-you-mean.js';
|
|
2
|
+
import { usageError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* The error for a first argument that is not a command, with the one fix
|
|
5
|
+
* most likely meant:
|
|
6
|
+
*
|
|
7
|
+
* - a whole command passed as ONE argument (`ekanos "teams list"`, which a
|
|
8
|
+
* shell or an agent's tool call produces when it quotes the line), whose
|
|
9
|
+
* first word is a command → the same words as separate arguments;
|
|
10
|
+
* - a typo of a command (`ekanos tems`) → the closest command;
|
|
11
|
+
* - otherwise the command list.
|
|
12
|
+
*
|
|
13
|
+
* `suggestion` is the corrected command line, or null when there is none to
|
|
14
|
+
* offer. It is also what the `claude-code-hint` line carries.
|
|
15
|
+
*/
|
|
16
|
+
export function unknownCommand(given, rest, commands) {
|
|
17
|
+
const suggestion = suggestCommandLine(given, rest, commands);
|
|
18
|
+
const message = `Unknown command "${given}".`;
|
|
19
|
+
if (suggestion && /\s/.test(given.trim())) {
|
|
20
|
+
return {
|
|
21
|
+
suggestion,
|
|
22
|
+
error: usageError(message, `Did you mean "${suggestion}"? Each word is its own argument — ` +
|
|
23
|
+
`do not put the command in quotes.`),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (suggestion) {
|
|
27
|
+
return {
|
|
28
|
+
suggestion,
|
|
29
|
+
error: usageError(message, `Did you mean "${suggestion}"?`),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
suggestion: null,
|
|
34
|
+
error: usageError(message, `Run one of: ${commands.join(', ')}. See "ekanos --help".`),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function suggestCommandLine(given, rest, commands) {
|
|
38
|
+
var _a;
|
|
39
|
+
const words = given.trim().split(/\s+/);
|
|
40
|
+
const head = (_a = words[0]) !== null && _a !== void 0 ? _a : '';
|
|
41
|
+
const corrected = commands.includes(head) ? head : suggestKey(head, commands);
|
|
42
|
+
if (!corrected)
|
|
43
|
+
return null;
|
|
44
|
+
return ['ekanos', corrected, ...words.slice(1), ...rest.map(shellWord)].join(' ');
|
|
45
|
+
}
|
|
46
|
+
/** A token as it would be typed: quoted when it holds whitespace. */
|
|
47
|
+
function shellWord(token) {
|
|
48
|
+
return /\s/.test(token) ? JSON.stringify(token) : token;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=unknown-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unknown-command.js","sourceRoot":"","sources":["../src/unknown-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAiB,UAAU,EAAE,MAAM,UAAU,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,IAAuB,EACvB,QAA2B;IAE3B,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,oBAAoB,KAAK,IAAI,CAAC;IAE9C,IAAI,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1C,OAAO;YACL,UAAU;YACV,KAAK,EAAE,UAAU,CACf,OAAO,EACP,iBAAiB,UAAU,qCAAqC;gBAC9D,mCAAmC,CACtC;SACF,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,OAAO;YACL,UAAU;YACV,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,iBAAiB,UAAU,IAAI,CAAC;SAC5D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,IAAI;QAChB,KAAK,EAAE,UAAU,CACf,OAAO,EACP,eAAe,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAC3D;KACF,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,KAAa,EACb,IAAuB,EACvB,QAA2B;;IAE3B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,IAAI,SAAG,KAAK,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE9E,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAC1E,GAAG,CACJ,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1D,CAAC","sourcesContent":["import { suggestKey } from './did-you-mean';\nimport { type CliError, usageError } from './errors';\n\n/**\n * The error for a first argument that is not a command, with the one fix\n * most likely meant:\n *\n * - a whole command passed as ONE argument (`ekanos \"teams list\"`, which a\n * shell or an agent's tool call produces when it quotes the line), whose\n * first word is a command → the same words as separate arguments;\n * - a typo of a command (`ekanos tems`) → the closest command;\n * - otherwise the command list.\n *\n * `suggestion` is the corrected command line, or null when there is none to\n * offer. It is also what the `claude-code-hint` line carries.\n */\nexport function unknownCommand(\n given: string,\n rest: readonly string[],\n commands: readonly string[],\n): { error: CliError; suggestion: string | null } {\n const suggestion = suggestCommandLine(given, rest, commands);\n const message = `Unknown command \"${given}\".`;\n\n if (suggestion && /\\s/.test(given.trim())) {\n return {\n suggestion,\n error: usageError(\n message,\n `Did you mean \"${suggestion}\"? Each word is its own argument — ` +\n `do not put the command in quotes.`,\n ),\n };\n }\n\n if (suggestion) {\n return {\n suggestion,\n error: usageError(message, `Did you mean \"${suggestion}\"?`),\n };\n }\n\n return {\n suggestion: null,\n error: usageError(\n message,\n `Run one of: ${commands.join(', ')}. See \"ekanos --help\".`,\n ),\n };\n}\n\nfunction suggestCommandLine(\n given: string,\n rest: readonly string[],\n commands: readonly string[],\n): string | null {\n const words = given.trim().split(/\\s+/);\n const head = words[0] ?? '';\n const corrected = commands.includes(head) ? head : suggestKey(head, commands);\n\n if (!corrected) return null;\n\n return ['ekanos', corrected, ...words.slice(1), ...rest.map(shellWord)].join(\n ' ',\n );\n}\n\n/** A token as it would be typed: quoted when it holds whitespace. */\nfunction shellWord(token: string): string {\n return /\\s/.test(token) ? JSON.stringify(token) : token;\n}\n"]}
|
|
@@ -5,7 +5,7 @@ import { collectDesignFindings } from './design-findings.js';
|
|
|
5
5
|
import { preconditionError } from './errors.js';
|
|
6
6
|
import { collectIconFindings } from './icon-findings.js';
|
|
7
7
|
import { loadDefinition } from './load-definition.js';
|
|
8
|
-
import { collectDocsFindings, collectHostCompilerRulesFindings, collectProjectFindings, } from './project-checks.js';
|
|
8
|
+
import { collectDocsFindings, collectHostCompilerRulesFindings, collectLintToolingFindings, collectProjectFindings, } from './project-checks.js';
|
|
9
9
|
/**
|
|
10
10
|
* The full findings pass shared by `validate` (which reports them) and
|
|
11
11
|
* `publish` (which refuses to submit on any error-severity finding). One
|
|
@@ -61,6 +61,7 @@ export async function collectAllFindings(loaded) {
|
|
|
61
61
|
// Cross-checks only mean something with more than one definition in hand.
|
|
62
62
|
findings.push(...collectCollisionFindings(definitions));
|
|
63
63
|
findings.push(...collectProjectFindings(loaded.projectDir));
|
|
64
|
+
findings.push(...collectLintToolingFindings(loaded.projectDir));
|
|
64
65
|
findings.push(...collectDocsFindings(loaded.project, loaded.projectDir));
|
|
65
66
|
findings.push(...collectIconFindings(loaded.projectDir));
|
|
66
67
|
findings.push(...collectDesignFindings(loaded.projectDir));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-findings.js","sourceRoot":"","sources":["../src/validate-findings.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DefinitionCollisionInput,\n Finding,\n} from '@ekanos/integration-schema';\nimport {\n collectCollisionFindings,\n collectDefinitionFindings,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { collectDesignFindings } from './design-findings';\nimport { preconditionError } from './errors';\nimport { collectIconFindings } from './icon-findings';\nimport { loadDefinition } from './load-definition';\nimport type { LoadedProject } from './project';\nimport {\n collectDocsFindings,\n collectHostCompilerRulesFindings,\n collectProjectFindings,\n} from './project-checks';\n\n/**\n * The full findings pass shared by `validate` (which reports them) and\n * `publish` (which refuses to submit on any error-severity finding). One\n * implementation so the publish gate can never drift from what `validate`\n * checks — a project that validates clean is, by construction, a project that\n * publish will accept locally.\n *\n * NOTE on schema skew: an earlier version of this function rewrote the\n * unrecognized-key hint when the project's `@ekanos/integration-schema` was\n * newer than the CLI's (see `schema-skew.ts`). That rewrite was dead code —\n * `assertSchemaNotSkewed` throws PRECONDITION_FAILED before either `validate`\n * or `publish` ever calls this function in that state, so a project-newer\n * finding can never reach here to be rewritten, and the precondition error\n * already names both versions and points at the fix. It was removed rather\n * than kept \"just in case\": if a future caller ever makes validate proceed\n * under skew instead of failing fast, THAT is when a rewrite here becomes\n * necessary again, and it should be reintroduced with a real caller driving\n * it, not tests that fake their own reachability.\n */\nexport async function collectAllFindings(\n loaded: LoadedProject,\n): Promise<Finding[]> {\n const findings: Finding[] = [];\n const definitions: DefinitionCollisionInput[] = [];\n\n for (const integration of loaded.integrations) {\n const result = await loadDefinition(\n integration.entryPath,\n loaded.projectDir,\n );\n\n if (result.ok) {\n findings.push(\n ...collectDefinitionFindings(result.definition, {\n file: integration.entryPath,\n }),\n );\n findings.push(\n ...collectSlugAgreementFindings(\n integration,\n result.definition as { slug?: unknown },\n ),\n );\n findings.push(\n ...collectVersionAgreementFindings(\n integration,\n result.definition as { version?: unknown },\n loaded.projectDir,\n ),\n );\n findings.push(\n ...collectOAuthSetupFindings(integration, result.definition),\n );\n definitions.push(result.definition as DefinitionCollisionInput);\n continue;\n }\n\n if (result.kind === 'rejected') {\n // The module loaded but the SDK/schema rejected the definition at import\n // time — surface it as a validation finding rather than a crash.\n findings.push({\n check: 'definition.load',\n severity: 'error',\n file: integration.entryPath,\n message: result.message,\n hint:\n 'Fix the integration definition so defineIntegration() accepts it, ' +\n 'then re-run validate.',\n });\n continue;\n }\n\n // A genuine module-load failure is a precondition, not a finding.\n throw preconditionError(\n `Could not load the integration definition for \"${integration.slug}\": ` +\n result.message,\n 'Ensure the entry module and its installed dependencies load under ' +\n 'Node, then re-run validate.',\n );\n }\n\n // Cross-checks only mean something with more than one definition in hand.\n findings.push(...collectCollisionFindings(definitions));\n findings.push(...collectProjectFindings(loaded.projectDir));\n findings.push(...collectDocsFindings(loaded.project, loaded.projectDir));\n findings.push(...collectIconFindings(loaded.projectDir));\n findings.push(...collectDesignFindings(loaded.projectDir));\n findings.push(...collectHostCompilerRulesFindings(loaded.projectDir));\n\n return findings;\n}\n\n/**\n * `ekanos.json` and the definition each carry a slug, and nothing compared\n * them: a project could declare `something-else` while the definition said\n * `repo-activity` and validate would report `{ ok: true, findings: [] }`.\n *\n * That is the identifier every surface addresses the integration by — the\n * harness route, the product slug, the widget id prefix, the MCP server — so\n * two sources of truth disagreeing is not a style question. It is an error,\n * not a warning, for the same reason a silent default is worse than a loud\n * one: the failure it causes shows up somewhere else entirely.\n */\nfunction collectSlugAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { slug?: unknown },\n): Finding[] {\n const declared = definition.slug;\n if (typeof declared !== 'string' || declared === integration.slug) return [];\n\n return [\n {\n check: 'project.slug-agreement',\n severity: 'error',\n file: integration.entryPath,\n message:\n `ekanos.json declares slug \"${integration.slug}\" for this entry, but ` +\n `the definition says \"${declared}\". The slug addresses the ` +\n 'integration everywhere — its harness route, its product record, its ' +\n 'widget ids — so the two must agree.',\n hint:\n `Change one to match the other: either set \"slug\": \"${declared}\" in ` +\n `ekanos.json, or pass slug: '${integration.slug}' to ` +\n 'defineIntegration().',\n },\n ];\n}\n\n/**\n * `package.json`'s `version` field and the `version` `defineIntegration()`\n * declares are two more independent sources of truth for the same fact —\n * this project shipped weather@0.1.1 with a package.json bump, but the\n * declaration itself still said 0.1.0. Generated seeds embed the\n * DECLARATION's version in their header, so a stale declaration produces a\n * seed that looks stale even though the package itself moved on.\n *\n * WARN, not error, unlike slug agreement: a mismatched version is a quality\n * signal a partner should fix, not a broken cross-reference that breaks\n * something else at runtime, so it must not block `publish`. And a project\n * with no package.json, or a package.json with no `version` field, has\n * nothing to compare the declaration against — skip rather than warn on\n * absence.\n */\nexport function collectVersionAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { version?: unknown },\n projectDir: string,\n): Finding[] {\n const declared = definition.version;\n if (typeof declared !== 'string') return [];\n\n const manifestPath = path.join(projectDir, 'package.json');\n if (!fs.existsSync(manifestPath)) return [];\n\n let manifest: unknown;\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n } catch {\n // Malformed package.json is npm's problem to report, not a validate\n // finding — nothing here can compare against an unparseable manifest.\n return [];\n }\n\n const packageVersion =\n typeof manifest === 'object' && manifest !== null\n ? (manifest as { version?: unknown }).version\n : undefined;\n if (typeof packageVersion !== 'string' || packageVersion === declared) {\n return [];\n }\n\n return [\n {\n check: 'project.version-agreement',\n severity: 'warn',\n file: integration.entryPath,\n message:\n `package.json declares version \"${packageVersion}\", but the ` +\n `defineIntegration() declaration for \"${integration.slug}\" still ` +\n `says \"${declared}\". Generated seed headers embed the ` +\n \"declaration's version, so a stale declaration ships stale-looking \" +\n 'metadata even though the package itself moved on.',\n hint:\n `Update the \"version\" passed to defineIntegration() in ` +\n `${integration.entryPath} to match package.json's \"${packageVersion}\".`,\n },\n ];\n}\n\n/**\n * An OAuth connection with no `setup` steps leaves whoever creates its app —\n * the Source admin (`ekanos apps`) or each team — to work out the provider's\n * console alone. A warning, not an error: the connection works without it.\n */\nexport function collectOAuthSetupFindings(\n integration: { entryPath: string },\n definition: unknown,\n): Finding[] {\n if (typeof definition !== 'object' || definition === null) return [];\n const { oauth, oauthConnections } = definition as {\n oauth?: { setup?: unknown; teamApp?: unknown };\n oauthConnections?: Record<string, { setup?: unknown; teamApp?: unknown }>;\n };\n\n type Connection = { setup?: unknown; teamApp?: unknown };\n const connections: Array<readonly [string, Connection]> = [\n ...(oauth ? [['oauth', oauth] as const] : []),\n ...Object.entries(oauthConnections ?? {}).map(\n ([id, connection]) => [`oauthConnections.${id}`, connection] as const,\n ),\n ];\n\n return connections\n .filter(([, connection]) => connection.setup === undefined)\n .map(([where, connection]) => ({\n check: 'oauth.setup-missing',\n severity: 'warn' as const,\n file: integration.entryPath,\n message:\n `${where} has no setup steps, so ` +\n (connection.teamApp\n ? 'each team creating its app'\n : \"the Source admin creating the Source's app (ekanos apps set)\") +\n \" gets no guidance in the provider's console.\",\n hint:\n `Add \\`setup: { consoleUrl, steps: [...] }\\` to ${where}: where the app is ` +\n 'created, and the steps in order. Write {callbackUrl} and {scopes} where ' +\n 'Ekanos should fill in the exact redirect URI and scopes.',\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-findings.js","sourceRoot":"","sources":["../src/validate-findings.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DefinitionCollisionInput,\n Finding,\n} from '@ekanos/integration-schema';\nimport {\n collectCollisionFindings,\n collectDefinitionFindings,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { collectDesignFindings } from './design-findings';\nimport { preconditionError } from './errors';\nimport { collectIconFindings } from './icon-findings';\nimport { loadDefinition } from './load-definition';\nimport type { LoadedProject } from './project';\nimport {\n collectDocsFindings,\n collectHostCompilerRulesFindings,\n collectLintToolingFindings,\n collectProjectFindings,\n} from './project-checks';\n\n/**\n * The full findings pass shared by `validate` (which reports them) and\n * `publish` (which refuses to submit on any error-severity finding). One\n * implementation so the publish gate can never drift from what `validate`\n * checks — a project that validates clean is, by construction, a project that\n * publish will accept locally.\n *\n * NOTE on schema skew: an earlier version of this function rewrote the\n * unrecognized-key hint when the project's `@ekanos/integration-schema` was\n * newer than the CLI's (see `schema-skew.ts`). That rewrite was dead code —\n * `assertSchemaNotSkewed` throws PRECONDITION_FAILED before either `validate`\n * or `publish` ever calls this function in that state, so a project-newer\n * finding can never reach here to be rewritten, and the precondition error\n * already names both versions and points at the fix. It was removed rather\n * than kept \"just in case\": if a future caller ever makes validate proceed\n * under skew instead of failing fast, THAT is when a rewrite here becomes\n * necessary again, and it should be reintroduced with a real caller driving\n * it, not tests that fake their own reachability.\n */\nexport async function collectAllFindings(\n loaded: LoadedProject,\n): Promise<Finding[]> {\n const findings: Finding[] = [];\n const definitions: DefinitionCollisionInput[] = [];\n\n for (const integration of loaded.integrations) {\n const result = await loadDefinition(\n integration.entryPath,\n loaded.projectDir,\n );\n\n if (result.ok) {\n findings.push(\n ...collectDefinitionFindings(result.definition, {\n file: integration.entryPath,\n }),\n );\n findings.push(\n ...collectSlugAgreementFindings(\n integration,\n result.definition as { slug?: unknown },\n ),\n );\n findings.push(\n ...collectVersionAgreementFindings(\n integration,\n result.definition as { version?: unknown },\n loaded.projectDir,\n ),\n );\n findings.push(\n ...collectOAuthSetupFindings(integration, result.definition),\n );\n definitions.push(result.definition as DefinitionCollisionInput);\n continue;\n }\n\n if (result.kind === 'rejected') {\n // The module loaded but the SDK/schema rejected the definition at import\n // time — surface it as a validation finding rather than a crash.\n findings.push({\n check: 'definition.load',\n severity: 'error',\n file: integration.entryPath,\n message: result.message,\n hint:\n 'Fix the integration definition so defineIntegration() accepts it, ' +\n 'then re-run validate.',\n });\n continue;\n }\n\n // A genuine module-load failure is a precondition, not a finding.\n throw preconditionError(\n `Could not load the integration definition for \"${integration.slug}\": ` +\n result.message,\n 'Ensure the entry module and its installed dependencies load under ' +\n 'Node, then re-run validate.',\n );\n }\n\n // Cross-checks only mean something with more than one definition in hand.\n findings.push(...collectCollisionFindings(definitions));\n findings.push(...collectProjectFindings(loaded.projectDir));\n findings.push(...collectLintToolingFindings(loaded.projectDir));\n findings.push(...collectDocsFindings(loaded.project, loaded.projectDir));\n findings.push(...collectIconFindings(loaded.projectDir));\n findings.push(...collectDesignFindings(loaded.projectDir));\n findings.push(...collectHostCompilerRulesFindings(loaded.projectDir));\n\n return findings;\n}\n\n/**\n * `ekanos.json` and the definition each carry a slug, and nothing compared\n * them: a project could declare `something-else` while the definition said\n * `repo-activity` and validate would report `{ ok: true, findings: [] }`.\n *\n * That is the identifier every surface addresses the integration by — the\n * harness route, the product slug, the widget id prefix, the MCP server — so\n * two sources of truth disagreeing is not a style question. It is an error,\n * not a warning, for the same reason a silent default is worse than a loud\n * one: the failure it causes shows up somewhere else entirely.\n */\nfunction collectSlugAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { slug?: unknown },\n): Finding[] {\n const declared = definition.slug;\n if (typeof declared !== 'string' || declared === integration.slug) return [];\n\n return [\n {\n check: 'project.slug-agreement',\n severity: 'error',\n file: integration.entryPath,\n message:\n `ekanos.json declares slug \"${integration.slug}\" for this entry, but ` +\n `the definition says \"${declared}\". The slug addresses the ` +\n 'integration everywhere — its harness route, its product record, its ' +\n 'widget ids — so the two must agree.',\n hint:\n `Change one to match the other: either set \"slug\": \"${declared}\" in ` +\n `ekanos.json, or pass slug: '${integration.slug}' to ` +\n 'defineIntegration().',\n },\n ];\n}\n\n/**\n * `package.json`'s `version` field and the `version` `defineIntegration()`\n * declares are two more independent sources of truth for the same fact —\n * this project shipped weather@0.1.1 with a package.json bump, but the\n * declaration itself still said 0.1.0. Generated seeds embed the\n * DECLARATION's version in their header, so a stale declaration produces a\n * seed that looks stale even though the package itself moved on.\n *\n * WARN, not error, unlike slug agreement: a mismatched version is a quality\n * signal a partner should fix, not a broken cross-reference that breaks\n * something else at runtime, so it must not block `publish`. And a project\n * with no package.json, or a package.json with no `version` field, has\n * nothing to compare the declaration against — skip rather than warn on\n * absence.\n */\nexport function collectVersionAgreementFindings(\n integration: { slug: string; entry: string; entryPath: string },\n definition: { version?: unknown },\n projectDir: string,\n): Finding[] {\n const declared = definition.version;\n if (typeof declared !== 'string') return [];\n\n const manifestPath = path.join(projectDir, 'package.json');\n if (!fs.existsSync(manifestPath)) return [];\n\n let manifest: unknown;\n try {\n manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n } catch {\n // Malformed package.json is npm's problem to report, not a validate\n // finding — nothing here can compare against an unparseable manifest.\n return [];\n }\n\n const packageVersion =\n typeof manifest === 'object' && manifest !== null\n ? (manifest as { version?: unknown }).version\n : undefined;\n if (typeof packageVersion !== 'string' || packageVersion === declared) {\n return [];\n }\n\n return [\n {\n check: 'project.version-agreement',\n severity: 'warn',\n file: integration.entryPath,\n message:\n `package.json declares version \"${packageVersion}\", but the ` +\n `defineIntegration() declaration for \"${integration.slug}\" still ` +\n `says \"${declared}\". Generated seed headers embed the ` +\n \"declaration's version, so a stale declaration ships stale-looking \" +\n 'metadata even though the package itself moved on.',\n hint:\n `Update the \"version\" passed to defineIntegration() in ` +\n `${integration.entryPath} to match package.json's \"${packageVersion}\".`,\n },\n ];\n}\n\n/**\n * An OAuth connection with no `setup` steps leaves whoever creates its app —\n * the Source admin (`ekanos apps`) or each team — to work out the provider's\n * console alone. A warning, not an error: the connection works without it.\n */\nexport function collectOAuthSetupFindings(\n integration: { entryPath: string },\n definition: unknown,\n): Finding[] {\n if (typeof definition !== 'object' || definition === null) return [];\n const { oauth, oauthConnections } = definition as {\n oauth?: { setup?: unknown; teamApp?: unknown };\n oauthConnections?: Record<string, { setup?: unknown; teamApp?: unknown }>;\n };\n\n type Connection = { setup?: unknown; teamApp?: unknown };\n const connections: Array<readonly [string, Connection]> = [\n ...(oauth ? [['oauth', oauth] as const] : []),\n ...Object.entries(oauthConnections ?? {}).map(\n ([id, connection]) => [`oauthConnections.${id}`, connection] as const,\n ),\n ];\n\n return connections\n .filter(([, connection]) => connection.setup === undefined)\n .map(([where, connection]) => ({\n check: 'oauth.setup-missing',\n severity: 'warn' as const,\n file: integration.entryPath,\n message:\n `${where} has no setup steps, so ` +\n (connection.teamApp\n ? 'each team creating its app'\n : \"the Source admin creating the Source's app (ekanos apps set)\") +\n \" gets no guidance in the provider's console.\",\n hint:\n `Add \\`setup: { consoleUrl, steps: [...] }\\` to ${where}: where the app is ` +\n 'created, and the steps in order. Write {callbackUrl} and {scopes} where ' +\n 'Ekanos should fill in the exact redirect URI and scopes.',\n }));\n}\n"]}
|