@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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type TeamWorkflowApplied, type TeamWorkflowApplyRequest, type TeamWorkflowApprovalDecideRequest, type TeamWorkflowApprovalDecided, type TeamWorkflowApprovalList, type TeamWorkflowDetail, type TeamWorkflowList, type TeamWorkflowRunCancelled, type TeamWorkflowRunDetail, type TeamWorkflowRunList, type TeamWorkflowRunStartRequest, type TeamWorkflowRunStarted, type TeamWorkflowStatusChanged, type TeamWorkflowStatusRequest } from '@ekanos/integration-schema';
|
|
2
|
+
/**
|
|
3
|
+
* The CLI's client for a team's workflows — `ekanos workflows`.
|
|
4
|
+
*
|
|
5
|
+
* GET /api/partner/teams/<team>/workflows → TeamWorkflowList
|
|
6
|
+
* POST /api/partner/teams/<team>/workflows → TeamWorkflowApplied
|
|
7
|
+
* GET /api/partner/teams/<team>/workflows/<id> → TeamWorkflowDetail
|
|
8
|
+
* POST /api/partner/teams/<team>/workflows/<id>/status → TeamWorkflowStatusChanged
|
|
9
|
+
* POST /api/partner/teams/<team>/workflows/<id>/runs → TeamWorkflowRunStarted
|
|
10
|
+
* GET /api/partner/teams/<team>/workflows/runs → TeamWorkflowRunList
|
|
11
|
+
* GET /api/partner/teams/<team>/workflows/runs/<id> → TeamWorkflowRunDetail
|
|
12
|
+
* POST /api/partner/teams/<team>/workflows/runs/<id>/cancel → TeamWorkflowRunCancelled
|
|
13
|
+
* GET /api/partner/teams/<team>/workflows/approvals → TeamWorkflowApprovalList
|
|
14
|
+
* POST /api/partner/teams/<team>/workflows/approvals/<id> → TeamWorkflowApprovalDecided
|
|
15
|
+
*
|
|
16
|
+
* Every path carries `?source=<slug>`.
|
|
17
|
+
*/
|
|
18
|
+
export type WorkflowsApiResult<T> = {
|
|
19
|
+
status: 'ok';
|
|
20
|
+
data: T;
|
|
21
|
+
} | {
|
|
22
|
+
status: 'unauthorized';
|
|
23
|
+
}
|
|
24
|
+
/** Activation stopped only on what Custom Code reaches: ask, then resend. */
|
|
25
|
+
| {
|
|
26
|
+
status: 'needs-access';
|
|
27
|
+
error: string;
|
|
28
|
+
codeAccess: CodeAccess[];
|
|
29
|
+
};
|
|
30
|
+
export interface CodeAccess {
|
|
31
|
+
stepId: string;
|
|
32
|
+
effect: 'read' | 'write';
|
|
33
|
+
egressHosts: string[];
|
|
34
|
+
tools: string[];
|
|
35
|
+
dependencies: string[];
|
|
36
|
+
reviewSummary: string | null;
|
|
37
|
+
}
|
|
38
|
+
interface TeamTarget {
|
|
39
|
+
source: string;
|
|
40
|
+
team: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function listWorkflows(host: string, accessToken: string, target: TeamTarget & {
|
|
43
|
+
all: boolean;
|
|
44
|
+
}): Promise<WorkflowsApiResult<TeamWorkflowList>>;
|
|
45
|
+
export declare function showWorkflow(host: string, accessToken: string, target: TeamTarget & {
|
|
46
|
+
workflow: string;
|
|
47
|
+
}): Promise<WorkflowsApiResult<TeamWorkflowDetail>>;
|
|
48
|
+
export declare function applyWorkflow(host: string, accessToken: string, target: TeamTarget, body: TeamWorkflowApplyRequest): Promise<WorkflowsApiResult<TeamWorkflowApplied>>;
|
|
49
|
+
export declare function setWorkflowStatus(host: string, accessToken: string, target: TeamTarget & {
|
|
50
|
+
workflow: string;
|
|
51
|
+
}, body: TeamWorkflowStatusRequest): Promise<WorkflowsApiResult<TeamWorkflowStatusChanged>>;
|
|
52
|
+
export declare function startWorkflowRun(host: string, accessToken: string, target: TeamTarget & {
|
|
53
|
+
workflow: string;
|
|
54
|
+
}, body: TeamWorkflowRunStartRequest): Promise<WorkflowsApiResult<TeamWorkflowRunStarted>>;
|
|
55
|
+
export declare function listWorkflowRuns(host: string, accessToken: string, target: TeamTarget & {
|
|
56
|
+
workflow?: string;
|
|
57
|
+
status?: string;
|
|
58
|
+
}): Promise<WorkflowsApiResult<TeamWorkflowRunList>>;
|
|
59
|
+
export declare function showWorkflowRun(host: string, accessToken: string, target: TeamTarget & {
|
|
60
|
+
runId: string;
|
|
61
|
+
}): Promise<WorkflowsApiResult<TeamWorkflowRunDetail>>;
|
|
62
|
+
export declare function cancelWorkflowRun(host: string, accessToken: string, target: TeamTarget & {
|
|
63
|
+
runId: string;
|
|
64
|
+
}): Promise<WorkflowsApiResult<TeamWorkflowRunCancelled>>;
|
|
65
|
+
export declare function listWorkflowApprovals(host: string, accessToken: string, target: TeamTarget): Promise<WorkflowsApiResult<TeamWorkflowApprovalList>>;
|
|
66
|
+
export declare function decideWorkflowApproval(host: string, accessToken: string, target: TeamTarget & {
|
|
67
|
+
approvalId: string;
|
|
68
|
+
}, body: TeamWorkflowApprovalDecideRequest): Promise<WorkflowsApiResult<TeamWorkflowApprovalDecided>>;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { TeamWorkflowAppliedSchema, TeamWorkflowApprovalDecidedSchema, TeamWorkflowApprovalListSchema, TeamWorkflowDetailSchema, TeamWorkflowListSchema, TeamWorkflowRunCancelledSchema, TeamWorkflowRunDetailSchema, TeamWorkflowRunListSchema, TeamWorkflowRunStartedSchema, TeamWorkflowStatusChangedSchema, } from '@ekanos/integration-schema';
|
|
2
|
+
import { request } from './auth/ekanos-api.js';
|
|
3
|
+
import { authRequiredError, forbiddenError, invalidStateError, networkError, notFoundError, usageError, validationError, } from './errors.js';
|
|
4
|
+
const segment = encodeURIComponent;
|
|
5
|
+
export function listWorkflows(host, accessToken, target) {
|
|
6
|
+
return call(host, accessToken, TeamWorkflowListSchema, {
|
|
7
|
+
method: 'GET',
|
|
8
|
+
path: base(target),
|
|
9
|
+
query: Object.assign({ source: target.source }, (target.all ? { all: '1' } : {})),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function showWorkflow(host, accessToken, target) {
|
|
13
|
+
return call(host, accessToken, TeamWorkflowDetailSchema, {
|
|
14
|
+
method: 'GET',
|
|
15
|
+
path: `${base(target)}/${segment(target.workflow)}`,
|
|
16
|
+
query: { source: target.source },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function applyWorkflow(host, accessToken, target, body) {
|
|
20
|
+
return call(host, accessToken, TeamWorkflowAppliedSchema, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
path: base(target),
|
|
23
|
+
query: { source: target.source },
|
|
24
|
+
body,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function setWorkflowStatus(host, accessToken, target, body) {
|
|
28
|
+
return call(host, accessToken, TeamWorkflowStatusChangedSchema, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
path: `${base(target)}/${segment(target.workflow)}/status`,
|
|
31
|
+
query: { source: target.source },
|
|
32
|
+
body,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function startWorkflowRun(host, accessToken, target, body) {
|
|
36
|
+
return call(host, accessToken, TeamWorkflowRunStartedSchema, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
path: `${base(target)}/${segment(target.workflow)}/runs`,
|
|
39
|
+
query: { source: target.source },
|
|
40
|
+
body,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function listWorkflowRuns(host, accessToken, target) {
|
|
44
|
+
return call(host, accessToken, TeamWorkflowRunListSchema, {
|
|
45
|
+
method: 'GET',
|
|
46
|
+
path: `${base(target)}/runs`,
|
|
47
|
+
query: Object.assign(Object.assign({ source: target.source }, (target.workflow ? { workflow: target.workflow } : {})), (target.status ? { status: target.status } : {})),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function showWorkflowRun(host, accessToken, target) {
|
|
51
|
+
return call(host, accessToken, TeamWorkflowRunDetailSchema, {
|
|
52
|
+
method: 'GET',
|
|
53
|
+
path: `${base(target)}/runs/${segment(target.runId)}`,
|
|
54
|
+
query: { source: target.source },
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
export function cancelWorkflowRun(host, accessToken, target) {
|
|
58
|
+
return call(host, accessToken, TeamWorkflowRunCancelledSchema, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
path: `${base(target)}/runs/${segment(target.runId)}/cancel`,
|
|
61
|
+
query: { source: target.source },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export function listWorkflowApprovals(host, accessToken, target) {
|
|
65
|
+
return call(host, accessToken, TeamWorkflowApprovalListSchema, {
|
|
66
|
+
method: 'GET',
|
|
67
|
+
path: `${base(target)}/approvals`,
|
|
68
|
+
query: { source: target.source },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
export function decideWorkflowApproval(host, accessToken, target, body) {
|
|
72
|
+
return call(host, accessToken, TeamWorkflowApprovalDecidedSchema, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
path: `${base(target)}/approvals/${segment(target.approvalId)}`,
|
|
75
|
+
query: { source: target.source },
|
|
76
|
+
body,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function base(target) {
|
|
80
|
+
return `/api/partner/teams/${segment(target.team)}/workflows`;
|
|
81
|
+
}
|
|
82
|
+
async function call(host, accessToken, schema, init) {
|
|
83
|
+
const response = await request(`${host}${init.path}?${new URLSearchParams(init.query)}`, {
|
|
84
|
+
method: init.method,
|
|
85
|
+
headers: Object.assign({ accept: 'application/json', authorization: `Bearer ${accessToken}` }, (init.body === undefined
|
|
86
|
+
? {}
|
|
87
|
+
: { 'content-type': 'application/json' })),
|
|
88
|
+
body: init.body === undefined ? undefined : JSON.stringify(init.body),
|
|
89
|
+
});
|
|
90
|
+
if (response.status === 401 ||
|
|
91
|
+
(response.status >= 300 && response.status < 400)) {
|
|
92
|
+
return { status: 'unauthorized' };
|
|
93
|
+
}
|
|
94
|
+
const body = await readOptionalJson(response);
|
|
95
|
+
const code = typeof body.code === 'string' ? body.code : null;
|
|
96
|
+
const message = typeof body.error === 'string' && body.error ? body.error : null;
|
|
97
|
+
if (response.status === 403 && code === 'MFA_REQUIRED') {
|
|
98
|
+
throw authRequiredError(message !== null && message !== void 0 ? message : `${host} requires multi-factor authentication.`, 'Complete MFA in the browser, then run "ekanos login" again.');
|
|
99
|
+
}
|
|
100
|
+
if (response.status === 403) {
|
|
101
|
+
throw forbiddenError(message !== null && message !== void 0 ? message : 'Not permitted on this Source.', code === 'SOURCE_ADMIN_REQUIRED'
|
|
102
|
+
? "Only a Source admin manages its teams' workflows."
|
|
103
|
+
: 'Run "ekanos sources" to list the sources you hold a seat on.');
|
|
104
|
+
}
|
|
105
|
+
if (response.status === 404) {
|
|
106
|
+
throw notFoundError(message !== null && message !== void 0 ? message : 'Not found.', code === 'TEAM_NOT_FOUND'
|
|
107
|
+
? 'Run "ekanos teams list" to see the teams on this Source.'
|
|
108
|
+
: code === 'WORKFLOW_NOT_FOUND'
|
|
109
|
+
? 'Run "ekanos workflows list --team <slug>" for the team\'s workflows (a member\'s personal workflow is theirs alone).'
|
|
110
|
+
: code === 'RUN_NOT_FOUND'
|
|
111
|
+
? 'Run "ekanos workflows runs list --team <slug>" for the team\'s runs.'
|
|
112
|
+
: code === 'APPROVAL_NOT_FOUND'
|
|
113
|
+
? 'Run "ekanos workflows approvals list --team <slug>" for what is waiting.'
|
|
114
|
+
: 'Run "ekanos sources" to list the sources you hold a seat on.');
|
|
115
|
+
}
|
|
116
|
+
if (response.status === 409 && code === 'CODE_ACCESS_NEEDS_APPROVAL') {
|
|
117
|
+
const details = Array.isArray(body.codeAccess) ? body.codeAccess : [];
|
|
118
|
+
return {
|
|
119
|
+
status: 'needs-access',
|
|
120
|
+
error: message !== null && message !== void 0 ? message : 'Custom Code access needs your approval.',
|
|
121
|
+
codeAccess: details.filter(isCodeAccess),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (response.status === 422) {
|
|
125
|
+
throw validationError(message !== null && message !== void 0 ? message : 'The host refused the workflow definition.', code === 'INVALID_DEFINITION'
|
|
126
|
+
? 'Fix the definition and apply it again; nothing was saved.'
|
|
127
|
+
: 'The stored definition no longer validates: fix it with "ekanos workflows apply <file> --update <id>".');
|
|
128
|
+
}
|
|
129
|
+
if (response.status === 409 || response.status === 502) {
|
|
130
|
+
throw invalidStateError(message !== null && message !== void 0 ? message : 'The host refused the request in its current state.', code === 'WORKFLOWS_EXPERIENCE_OFF'
|
|
131
|
+
? 'Ask Ekanos to turn on Workflows for this Source: only a super-admin can ("ekanos sources products" shows it as off).'
|
|
132
|
+
: code === 'AMBIGUOUS_WORKFLOW'
|
|
133
|
+
? 'Name it by id: "ekanos workflows list --team <slug>" shows each one\'s.'
|
|
134
|
+
: code === 'WORKFLOW_ARCHIVED'
|
|
135
|
+
? 'Restore it in the app first, or apply without --update to create a new draft.'
|
|
136
|
+
: code === 'ALREADY_DECIDED' || code === 'APPROVAL_EXPIRED'
|
|
137
|
+
? 'Run "ekanos workflows approvals list --team <slug>" for what is still waiting.'
|
|
138
|
+
: code === 'RUN_FINISHED'
|
|
139
|
+
? 'Nothing to stop. "ekanos workflows runs show <run-id> --team <slug>" shows how it ended.'
|
|
140
|
+
: code === 'CANCEL_FAILED'
|
|
141
|
+
? 'Its status is reconciled automatically; check "ekanos workflows runs show <run-id>" shortly.'
|
|
142
|
+
: code === 'RESUME_FAILED'
|
|
143
|
+
? 'The decision is saved; the run picks it up shortly. Check with "ekanos workflows runs show <run-id>".'
|
|
144
|
+
: code === 'RUN_REFUSED'
|
|
145
|
+
? 'A live run needs an active workflow ("ekanos workflows enable"); "--dry-run" rehearses a draft.'
|
|
146
|
+
: 'Run "ekanos workflows show <id> --team <slug>" for its status and what blocks it.');
|
|
147
|
+
}
|
|
148
|
+
if (response.status === 400) {
|
|
149
|
+
throw usageError(message !== null && message !== void 0 ? message : 'The host refused the request.', 'See "ekanos workflows --help".');
|
|
150
|
+
}
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
throw networkError(`${host}${init.path} responded ${response.status}.`, response.status >= 500
|
|
153
|
+
? 'The Ekanos deployment returned a server error. Retry shortly.'
|
|
154
|
+
: 'Confirm the host runs a build that includes the workflows routes.');
|
|
155
|
+
}
|
|
156
|
+
const parsed = schema.safeParse(body.data);
|
|
157
|
+
if (!parsed.success) {
|
|
158
|
+
throw networkError(`${host}${init.path} answered in a shape this CLI does not read.`, 'Run "ekanos upgrade" — the CLI and the host disagree on the workflows contract.');
|
|
159
|
+
}
|
|
160
|
+
return { status: 'ok', data: parsed.data };
|
|
161
|
+
}
|
|
162
|
+
function isCodeAccess(value) {
|
|
163
|
+
if (typeof value !== 'object' || value === null)
|
|
164
|
+
return false;
|
|
165
|
+
const entry = value;
|
|
166
|
+
return (typeof entry.stepId === 'string' &&
|
|
167
|
+
(entry.effect === 'read' || entry.effect === 'write') &&
|
|
168
|
+
Array.isArray(entry.egressHosts) &&
|
|
169
|
+
Array.isArray(entry.tools));
|
|
170
|
+
}
|
|
171
|
+
async function readOptionalJson(response) {
|
|
172
|
+
try {
|
|
173
|
+
const parsed = await response.json();
|
|
174
|
+
return typeof parsed === 'object' && parsed !== null
|
|
175
|
+
? parsed
|
|
176
|
+
: {};
|
|
177
|
+
}
|
|
178
|
+
catch (_a) {
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=workflows-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows-api.js","sourceRoot":"","sources":["../src/workflows-api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type TeamWorkflowApplied,\n TeamWorkflowAppliedSchema,\n type TeamWorkflowApplyRequest,\n type TeamWorkflowApprovalDecideRequest,\n type TeamWorkflowApprovalDecided,\n TeamWorkflowApprovalDecidedSchema,\n type TeamWorkflowApprovalList,\n TeamWorkflowApprovalListSchema,\n type TeamWorkflowDetail,\n TeamWorkflowDetailSchema,\n type TeamWorkflowList,\n TeamWorkflowListSchema,\n type TeamWorkflowRunCancelled,\n TeamWorkflowRunCancelledSchema,\n type TeamWorkflowRunDetail,\n TeamWorkflowRunDetailSchema,\n type TeamWorkflowRunList,\n TeamWorkflowRunListSchema,\n type TeamWorkflowRunStartRequest,\n type TeamWorkflowRunStarted,\n TeamWorkflowRunStartedSchema,\n type TeamWorkflowStatusChanged,\n TeamWorkflowStatusChangedSchema,\n type TeamWorkflowStatusRequest,\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 team's workflows — `ekanos workflows`.\n *\n * GET /api/partner/teams/<team>/workflows → TeamWorkflowList\n * POST /api/partner/teams/<team>/workflows → TeamWorkflowApplied\n * GET /api/partner/teams/<team>/workflows/<id> → TeamWorkflowDetail\n * POST /api/partner/teams/<team>/workflows/<id>/status → TeamWorkflowStatusChanged\n * POST /api/partner/teams/<team>/workflows/<id>/runs → TeamWorkflowRunStarted\n * GET /api/partner/teams/<team>/workflows/runs → TeamWorkflowRunList\n * GET /api/partner/teams/<team>/workflows/runs/<id> → TeamWorkflowRunDetail\n * POST /api/partner/teams/<team>/workflows/runs/<id>/cancel → TeamWorkflowRunCancelled\n * GET /api/partner/teams/<team>/workflows/approvals → TeamWorkflowApprovalList\n * POST /api/partner/teams/<team>/workflows/approvals/<id> → TeamWorkflowApprovalDecided\n *\n * Every path carries `?source=<slug>`.\n */\n\nexport type WorkflowsApiResult<T> =\n | { status: 'ok'; data: T }\n | { status: 'unauthorized' }\n /** Activation stopped only on what Custom Code reaches: ask, then resend. */\n | { status: 'needs-access'; error: string; codeAccess: CodeAccess[] };\n\nexport interface CodeAccess {\n stepId: string;\n effect: 'read' | 'write';\n egressHosts: string[];\n tools: string[];\n dependencies: string[];\n reviewSummary: string | null;\n}\n\ninterface TeamTarget {\n source: string;\n team: string;\n}\n\nconst segment = encodeURIComponent;\n\nexport function listWorkflows(\n host: string,\n accessToken: string,\n target: TeamTarget & { all: boolean },\n): Promise<WorkflowsApiResult<TeamWorkflowList>> {\n return call(host, accessToken, TeamWorkflowListSchema, {\n method: 'GET',\n path: base(target),\n query: { source: target.source, ...(target.all ? { all: '1' } : {}) },\n });\n}\n\nexport function showWorkflow(\n host: string,\n accessToken: string,\n target: TeamTarget & { workflow: string },\n): Promise<WorkflowsApiResult<TeamWorkflowDetail>> {\n return call(host, accessToken, TeamWorkflowDetailSchema, {\n method: 'GET',\n path: `${base(target)}/${segment(target.workflow)}`,\n query: { source: target.source },\n });\n}\n\nexport function applyWorkflow(\n host: string,\n accessToken: string,\n target: TeamTarget,\n body: TeamWorkflowApplyRequest,\n): Promise<WorkflowsApiResult<TeamWorkflowApplied>> {\n return call(host, accessToken, TeamWorkflowAppliedSchema, {\n method: 'POST',\n path: base(target),\n query: { source: target.source },\n body,\n });\n}\n\nexport function setWorkflowStatus(\n host: string,\n accessToken: string,\n target: TeamTarget & { workflow: string },\n body: TeamWorkflowStatusRequest,\n): Promise<WorkflowsApiResult<TeamWorkflowStatusChanged>> {\n return call(host, accessToken, TeamWorkflowStatusChangedSchema, {\n method: 'POST',\n path: `${base(target)}/${segment(target.workflow)}/status`,\n query: { source: target.source },\n body,\n });\n}\n\nexport function startWorkflowRun(\n host: string,\n accessToken: string,\n target: TeamTarget & { workflow: string },\n body: TeamWorkflowRunStartRequest,\n): Promise<WorkflowsApiResult<TeamWorkflowRunStarted>> {\n return call(host, accessToken, TeamWorkflowRunStartedSchema, {\n method: 'POST',\n path: `${base(target)}/${segment(target.workflow)}/runs`,\n query: { source: target.source },\n body,\n });\n}\n\nexport function listWorkflowRuns(\n host: string,\n accessToken: string,\n target: TeamTarget & { workflow?: string; status?: string },\n): Promise<WorkflowsApiResult<TeamWorkflowRunList>> {\n return call(host, accessToken, TeamWorkflowRunListSchema, {\n method: 'GET',\n path: `${base(target)}/runs`,\n query: {\n source: target.source,\n ...(target.workflow ? { workflow: target.workflow } : {}),\n ...(target.status ? { status: target.status } : {}),\n },\n });\n}\n\nexport function showWorkflowRun(\n host: string,\n accessToken: string,\n target: TeamTarget & { runId: string },\n): Promise<WorkflowsApiResult<TeamWorkflowRunDetail>> {\n return call(host, accessToken, TeamWorkflowRunDetailSchema, {\n method: 'GET',\n path: `${base(target)}/runs/${segment(target.runId)}`,\n query: { source: target.source },\n });\n}\n\nexport function cancelWorkflowRun(\n host: string,\n accessToken: string,\n target: TeamTarget & { runId: string },\n): Promise<WorkflowsApiResult<TeamWorkflowRunCancelled>> {\n return call(host, accessToken, TeamWorkflowRunCancelledSchema, {\n method: 'POST',\n path: `${base(target)}/runs/${segment(target.runId)}/cancel`,\n query: { source: target.source },\n });\n}\n\nexport function listWorkflowApprovals(\n host: string,\n accessToken: string,\n target: TeamTarget,\n): Promise<WorkflowsApiResult<TeamWorkflowApprovalList>> {\n return call(host, accessToken, TeamWorkflowApprovalListSchema, {\n method: 'GET',\n path: `${base(target)}/approvals`,\n query: { source: target.source },\n });\n}\n\nexport function decideWorkflowApproval(\n host: string,\n accessToken: string,\n target: TeamTarget & { approvalId: string },\n body: TeamWorkflowApprovalDecideRequest,\n): Promise<WorkflowsApiResult<TeamWorkflowApprovalDecided>> {\n return call(host, accessToken, TeamWorkflowApprovalDecidedSchema, {\n method: 'POST',\n path: `${base(target)}/approvals/${segment(target.approvalId)}`,\n query: { source: target.source },\n body,\n });\n}\n\nfunction base(target: TeamTarget): string {\n return `/api/partner/teams/${segment(target.team)}/workflows`;\n}\n\nasync function call<T>(\n host: string,\n accessToken: string,\n schema: z.ZodType<T>,\n init: {\n method: 'GET' | 'POST';\n path: string;\n query: Record<string, string>;\n body?: unknown;\n },\n): Promise<WorkflowsApiResult<T>> {\n const response = await request(\n `${host}${init.path}?${new URLSearchParams(init.query)}`,\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' workflows.\"\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 === 'WORKFLOW_NOT_FOUND'\n ? 'Run \"ekanos workflows list --team <slug>\" for the team\\'s workflows (a member\\'s personal workflow is theirs alone).'\n : code === 'RUN_NOT_FOUND'\n ? 'Run \"ekanos workflows runs list --team <slug>\" for the team\\'s runs.'\n : code === 'APPROVAL_NOT_FOUND'\n ? 'Run \"ekanos workflows approvals list --team <slug>\" for what is waiting.'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 409 && code === 'CODE_ACCESS_NEEDS_APPROVAL') {\n const details = Array.isArray(body.codeAccess) ? body.codeAccess : [];\n return {\n status: 'needs-access',\n error: message ?? 'Custom Code access needs your approval.',\n codeAccess: details.filter(isCodeAccess),\n };\n }\n if (response.status === 422) {\n throw validationError(\n message ?? 'The host refused the workflow definition.',\n code === 'INVALID_DEFINITION'\n ? 'Fix the definition and apply it again; nothing was saved.'\n : 'The stored definition no longer validates: fix it with \"ekanos workflows apply <file> --update <id>\".',\n );\n }\n if (response.status === 409 || response.status === 502) {\n throw invalidStateError(\n message ?? 'The host refused the request in its current state.',\n code === 'WORKFLOWS_EXPERIENCE_OFF'\n ? 'Ask Ekanos to turn on Workflows for this Source: only a super-admin can (\"ekanos sources products\" shows it as off).'\n : code === 'AMBIGUOUS_WORKFLOW'\n ? 'Name it by id: \"ekanos workflows list --team <slug>\" shows each one\\'s.'\n : code === 'WORKFLOW_ARCHIVED'\n ? 'Restore it in the app first, or apply without --update to create a new draft.'\n : code === 'ALREADY_DECIDED' || code === 'APPROVAL_EXPIRED'\n ? 'Run \"ekanos workflows approvals list --team <slug>\" for what is still waiting.'\n : code === 'RUN_FINISHED'\n ? 'Nothing to stop. \"ekanos workflows runs show <run-id> --team <slug>\" shows how it ended.'\n : code === 'CANCEL_FAILED'\n ? 'Its status is reconciled automatically; check \"ekanos workflows runs show <run-id>\" shortly.'\n : code === 'RESUME_FAILED'\n ? 'The decision is saved; the run picks it up shortly. Check with \"ekanos workflows runs show <run-id>\".'\n : code === 'RUN_REFUSED'\n ? 'A live run needs an active workflow (\"ekanos workflows enable\"); \"--dry-run\" rehearses a draft.'\n : 'Run \"ekanos workflows show <id> --team <slug>\" for its status and what blocks it.',\n );\n }\n if (response.status === 400) {\n throw usageError(\n message ?? 'The host refused the request.',\n 'See \"ekanos workflows --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 workflows routes.',\n );\n }\n\n const parsed = schema.safeParse(body.data);\n if (!parsed.success) {\n throw networkError(\n `${host}${init.path} answered in a shape this CLI does not read.`,\n 'Run \"ekanos upgrade\" — the CLI and the host disagree on the workflows contract.',\n );\n }\n return { status: 'ok', data: parsed.data };\n}\n\nfunction isCodeAccess(value: unknown): value is CodeAccess {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n typeof entry.stepId === 'string' &&\n (entry.effect === 'read' || entry.effect === 'write') &&\n Array.isArray(entry.egressHosts) &&\n Array.isArray(entry.tools)\n );\n}\n\nasync function readOptionalJson(\n response: Response,\n): Promise<Record<string, unknown>> {\n try {\n const parsed: unknown = await response.json();\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekanos/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The Ekanos partner toolchain CLI: scaffold, validate, and test an Ekanos integration against the published @ekanos packages. Agent-native — every verb speaks JSON with a stable exit-code taxonomy.",
|
|
6
6
|
"keywords": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@clack/prompts": "1.7.0",
|
|
38
|
-
"@ekanos/integration-schema": "0.
|
|
38
|
+
"@ekanos/integration-schema": "0.19.0",
|
|
39
39
|
"esbuild": "0.28.1",
|
|
40
40
|
"picocolors": "1.1.1"
|
|
41
41
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/node": "25.0.1",
|
|
45
45
|
"typescript": "^7.0.2",
|
|
46
46
|
"vitest": "4.1.10",
|
|
47
|
-
"zod": "4.6.
|
|
47
|
+
"zod": "4.6.7"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"zod": "^3.25.76 || ^4.0.0"
|
package/templates/AGENTS.md.tmpl
CHANGED
|
@@ -431,10 +431,12 @@ Icons are Font Awesome glyph names via `@ekanos/ui/icon`. This generated shell l
|
|
|
431
431
|
(`@fortawesome/fontawesome-free`) — a much smaller set than the Pro kit Ekanos
|
|
432
432
|
itself runs — so a name that's Pro-only (or just mistyped) renders a
|
|
433
433
|
circle-question disc instead of vanishing, and dev builds `console.warn` once
|
|
434
|
-
per name to catch it before a screenshot review does.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
434
|
+
per name to catch it before a screenshot review does. Write icon names
|
|
435
|
+
family-less (`fa-gear`, not `fa-light fa-gear`): the host's theme picks the
|
|
436
|
+
family, so a Source's icon style reaches your icons too, and
|
|
437
|
+
`design/no-default-icon-family` rejects `fa-light` / `fa-regular`. On Free,
|
|
438
|
+
families it lacks (`fa-light`, `fa-duotone`, `fa-thin`) still render as
|
|
439
|
+
`fa-solid`. Verify a glyph name against the
|
|
438
440
|
Free set (`pnpm --filter @ekanos/ui check:fa-free-names`, or
|
|
439
441
|
https://fontawesome.com/search?o=r&s=solid,regular,brands) before relying on
|
|
440
442
|
it looking like anything in particular.
|
|
@@ -30,7 +30,10 @@ and after upgrading `@ekanos/*` packages. The topic → URL map is in AGENTS.md.
|
|
|
30
30
|
tools and agent triggers, and the steps left to set each one up. If a product
|
|
31
31
|
already does what the user wants, propose setting it up (walk its
|
|
32
32
|
`setupSteps`, naming who does each one) instead of building it again.
|
|
33
|
-
`npx ekanos catalog <product> --json` shows one in full
|
|
33
|
+
`npx ekanos catalog <product> --json` shows one in full: each tool's
|
|
34
|
+
`inputSchema` (so you can see which other tool returns an id a tool needs)
|
|
35
|
+
and `connection` — who connects the product and whose connection an agent
|
|
36
|
+
run uses.
|
|
34
37
|
|
|
35
38
|
## Managed agents live in Ekanos
|
|
36
39
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# __DISPLAY_NAME__ (an Ekanos experience)
|
|
2
|
+
|
|
3
|
+
This project is an EXPERIENCE: widgets, pages and workflow templates that depend
|
|
4
|
+
on integrations and reach them only through their pinned contracts. It is not an
|
|
5
|
+
integration itself.
|
|
6
|
+
|
|
7
|
+
- The integrations it depends on are declared in `ekanos.json` "integrations"
|
|
8
|
+
(`name` = the integration, `version`, the `operations` it may call) and pinned in
|
|
9
|
+
`ekanos.lock.json` + `contracts/`. Add one:
|
|
10
|
+
`ekanos add <integration>@<version> --from-dir <dir>`.
|
|
11
|
+
Never edit `src/.ekanos/integrations.d.ts`; `ekanos codegen` writes it.
|
|
12
|
+
- Read: `useOperation(integration, 'tool/<name>', input)`. Write:
|
|
13
|
+
`useOperationMutation(integration, 'action/<name>')` (a person approves each write).
|
|
14
|
+
Server: `operation(integration, op, input)` from `@ekanos/sdk/experience/server`.
|
|
15
|
+
- Never import integration code (`@companydotcom/integration-*`, a path into an
|
|
16
|
+
integration repo, `@kit/*`). `ekanos check` and `ekanos build` fail on it.
|
|
17
|
+
- Build UI with `@ekanos/sdk/components` (`Widget.*`) and `@ekanos/ui`, semantic
|
|
18
|
+
tokens only.
|
|
19
|
+
- To try an unpublished integration, create `ekanos.local.json` (gitignored)
|
|
20
|
+
with an "integrations" entry pointing at the integration's folder. While any override is active `ekanos publish`
|
|
21
|
+
refuses.
|
|
22
|
+
- Loop: `ekanos check` then `ekanos build`.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lint config for __SLUG__.
|
|
3
|
+
*
|
|
4
|
+
* `@ekanos/sdk/eslint/experience` keeps integration code out of this project:
|
|
5
|
+
* no `@companydotcom/integration-*`, no path into an integration, no `@kit/*`,
|
|
6
|
+
* no computed `import()`. An experience XX * integrations (`useOperation`, `operation`, `step.tool`). `ekanos check` re-verifies
|
|
7
|
+
* the same rule against the real import graph and the built bundle.
|
|
8
|
+
*/
|
|
9
|
+
import experiencePreset from '@ekanos/sdk/eslint/experience';
|
|
10
|
+
import tsParser from '@typescript-eslint/parser';
|
|
11
|
+
|
|
12
|
+
export default [
|
|
13
|
+
{ ignores: ['dist/**', 'node_modules/**', '.ekanos/**', 'legacy/**'] },
|
|
14
|
+
{
|
|
15
|
+
name: '__SLUG__/parser',
|
|
16
|
+
files: ['src/**/*.ts', 'src/**/*.tsx'],
|
|
17
|
+
languageOptions: {
|
|
18
|
+
parser: tsParser,
|
|
19
|
+
ecmaVersion: 'latest',
|
|
20
|
+
sourceType: 'module',
|
|
21
|
+
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
...experiencePreset,
|
|
25
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build output (regenerated by `ekanos build`)
|
|
5
|
+
dist/
|
|
6
|
+
manifest.json
|
|
7
|
+
*.tsbuildinfo
|
|
8
|
+
|
|
9
|
+
# Per-developer: integration overrides and the generated dev harness (root only:
|
|
10
|
+
# src/.ekanos/integrations.d.ts is codegen output and IS committed). Never commit these;
|
|
11
|
+
# `ekanos check` fails if ekanos.local.json is tracked and `ekanos publish`
|
|
12
|
+
# refuses while an override is active.
|
|
13
|
+
ekanos.local.json
|
|
14
|
+
/.ekanos/
|
|
15
|
+
|
|
16
|
+
# Logs
|
|
17
|
+
*.log
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__SLUG__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "An Ekanos experience built with @ekanos/sdk.",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"manifest.json",
|
|
10
|
+
"ekanos.json",
|
|
11
|
+
"ekanos.lock.json",
|
|
12
|
+
"contracts"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"check": "npx ekanos check",
|
|
18
|
+
"build": "npx ekanos build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@ekanos/sdk": "^0.19.0",
|
|
22
|
+
"@ekanos/ui": "^0.19.0",
|
|
23
|
+
"@tanstack/react-query": "^5.101.4",
|
|
24
|
+
"react": "^19.2.8",
|
|
25
|
+
"react-dom": "^19.2.8",
|
|
26
|
+
"zod": "^3.25.76"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@ekanos/cli": "^0.17.0",
|
|
30
|
+
"@ekanos/harness": "^0.19.0",
|
|
31
|
+
"@tailwindcss/postcss": "^4.3.3",
|
|
32
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
33
|
+
"@types/react": "^19.2.0",
|
|
34
|
+
"@types/react-dom": "^19.2.0",
|
|
35
|
+
"eslint": "^10.11.0",
|
|
36
|
+
"next": "^16.0.0",
|
|
37
|
+
"react-hook-form": "^7.68.0",
|
|
38
|
+
"tailwindcss": "^4.3.3",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Your experience, declared in one object.
|
|
3
|
+
*
|
|
4
|
+
* The integrations this experience depends on live in ekanos.json "integrations",
|
|
5
|
+
* not here. Add one with:
|
|
6
|
+
*
|
|
7
|
+
* ekanos add <integration>@<version> --from-dir <contracts folder>
|
|
8
|
+
*
|
|
9
|
+
* That pins the integration's contract and generates src/.ekanos/integrations.d.ts,
|
|
10
|
+
* after which `useOperation('<integration>', 'tool/<name>')` is typed end to end.
|
|
11
|
+
*/
|
|
12
|
+
import { defineExperience } from '@ekanos/sdk/experience';
|
|
13
|
+
|
|
14
|
+
import { HelloWidget } from './widgets/hello-widget';
|
|
15
|
+
|
|
16
|
+
export default defineExperience({
|
|
17
|
+
slug: '__SLUG__',
|
|
18
|
+
name: '__DISPLAY_NAME__',
|
|
19
|
+
description: 'A starter experience. Replace this with what it does.',
|
|
20
|
+
sidebar: { section: '__SLUG__', icon: 'sparkles', label: '__DISPLAY_NAME__' },
|
|
21
|
+
widgets: [
|
|
22
|
+
{
|
|
23
|
+
id: 'hello',
|
|
24
|
+
title: 'Hello',
|
|
25
|
+
integrations: [],
|
|
26
|
+
width: 'half',
|
|
27
|
+
component: HelloWidget,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Widget } from '@ekanos/sdk/components';
|
|
2
|
+
import {
|
|
3
|
+
Stat,
|
|
4
|
+
StatDetail,
|
|
5
|
+
StatFigure,
|
|
6
|
+
StatLabel,
|
|
7
|
+
StatValue,
|
|
8
|
+
} from '@ekanos/ui/stat';
|
|
9
|
+
|
|
10
|
+
// A starter widget, built like an integration widget: the Widget.* compound
|
|
11
|
+
// API plus the kit's Stat, semantic tokens only, never an inline style.
|
|
12
|
+
//
|
|
13
|
+
// Once you have added an integration, read from it with a typed hook:
|
|
14
|
+
//
|
|
15
|
+
// import { useOperation } from '@ekanos/sdk/experience/client';
|
|
16
|
+
// const posts = useOperation('sanity', 'tool/list_posts', { limit: 10 });
|
|
17
|
+
//
|
|
18
|
+
// and write with useOperationMutation, which asks a person to approve first.
|
|
19
|
+
export function HelloWidget() {
|
|
20
|
+
return (
|
|
21
|
+
<Widget.DataState>
|
|
22
|
+
<Widget.Card>
|
|
23
|
+
<Widget.Header context="Since you scaffolded this" />
|
|
24
|
+
<Widget.Active>
|
|
25
|
+
<Widget.Body>
|
|
26
|
+
<Stat>
|
|
27
|
+
<StatLabel>Integrations</StatLabel>
|
|
28
|
+
<StatFigure>
|
|
29
|
+
<StatValue>0</StatValue>
|
|
30
|
+
</StatFigure>
|
|
31
|
+
<StatDetail>Run "ekanos add" to add an integration</StatDetail>
|
|
32
|
+
</Stat>
|
|
33
|
+
</Widget.Body>
|
|
34
|
+
</Widget.Active>
|
|
35
|
+
<Widget.Loading variant="stat" />
|
|
36
|
+
<Widget.Error />
|
|
37
|
+
</Widget.Card>
|
|
38
|
+
</Widget.DataState>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "ES2022"],
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src", "src/.ekanos/integrations.d.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist", ".ekanos", "legacy"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createEkanosApiHandlers } from '@ekanos/harness/api';
|
|
2
|
+
|
|
3
|
+
// Next treats a leading underscore folder as private, so this directory is
|
|
4
|
+
// literally named `%5F%5Fekanos` and serves /__ekanos/api/*.
|
|
5
|
+
const handlers = createEkanosApiHandlers();
|
|
6
|
+
|
|
7
|
+
export const GET = handlers.GET;
|
|
8
|
+
export const POST = handlers.POST;
|
|
9
|
+
export const PUT = handlers.PUT;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LegacyPreviewRedirect as default } from '@ekanos/harness/routes';
|