@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.
Files changed (287) hide show
  1. package/README.md +103 -8
  2. package/dist/auth/ekanos-api.d.ts +23 -0
  3. package/dist/auth/ekanos-api.js +33 -6
  4. package/dist/auth/ekanos-api.js.map +1 -1
  5. package/dist/commands/add.d.ts +2 -0
  6. package/dist/commands/add.js +118 -0
  7. package/dist/commands/add.js.map +1 -0
  8. package/dist/commands/agents.js +3 -2
  9. package/dist/commands/agents.js.map +1 -1
  10. package/dist/commands/apps.d.ts +11 -3
  11. package/dist/commands/apps.js +86 -28
  12. package/dist/commands/apps.js.map +1 -1
  13. package/dist/commands/audiences.d.ts +31 -0
  14. package/dist/commands/audiences.js +239 -0
  15. package/dist/commands/audiences.js.map +1 -0
  16. package/dist/commands/build.d.ts +2 -0
  17. package/dist/commands/build.js +41 -0
  18. package/dist/commands/build.js.map +1 -0
  19. package/dist/commands/catalog.d.ts +4 -2
  20. package/dist/commands/catalog.js +166 -35
  21. package/dist/commands/catalog.js.map +1 -1
  22. package/dist/commands/check.d.ts +2 -0
  23. package/dist/commands/check.js +43 -0
  24. package/dist/commands/check.js.map +1 -0
  25. package/dist/commands/codegen.d.ts +2 -0
  26. package/dist/commands/codegen.js +49 -0
  27. package/dist/commands/codegen.js.map +1 -0
  28. package/dist/commands/contract.d.ts +52 -0
  29. package/dist/commands/contract.js +300 -0
  30. package/dist/commands/contract.js.map +1 -0
  31. package/dist/commands/dev.d.ts +7 -0
  32. package/dist/commands/dev.js +186 -12
  33. package/dist/commands/dev.js.map +1 -1
  34. package/dist/commands/index-experience.d.ts +31 -0
  35. package/dist/commands/index-experience.js +21 -0
  36. package/dist/commands/index-experience.js.map +1 -0
  37. package/dist/commands/init.d.ts +7 -0
  38. package/dist/commands/init.js +12 -0
  39. package/dist/commands/init.js.map +1 -1
  40. package/dist/commands/login.d.ts +2 -0
  41. package/dist/commands/login.js +17 -0
  42. package/dist/commands/login.js.map +1 -1
  43. package/dist/commands/new.d.ts +2 -0
  44. package/dist/commands/new.js +39 -0
  45. package/dist/commands/new.js.map +1 -0
  46. package/dist/commands/publish.d.ts +59 -0
  47. package/dist/commands/publish.js +118 -65
  48. package/dist/commands/publish.js.map +1 -1
  49. package/dist/commands/runs.d.ts +7 -3
  50. package/dist/commands/runs.js +21 -5
  51. package/dist/commands/runs.js.map +1 -1
  52. package/dist/commands/scope-notice.d.ts +13 -0
  53. package/dist/commands/scope-notice.js +12 -4
  54. package/dist/commands/scope-notice.js.map +1 -1
  55. package/dist/commands/sources-roles.d.ts +5 -0
  56. package/dist/commands/sources-roles.js +235 -0
  57. package/dist/commands/sources-roles.js.map +1 -0
  58. package/dist/commands/sources.d.ts +5 -0
  59. package/dist/commands/sources.js +8 -1
  60. package/dist/commands/sources.js.map +1 -1
  61. package/dist/commands/sync.d.ts +2 -0
  62. package/dist/commands/sync.js +150 -0
  63. package/dist/commands/sync.js.map +1 -0
  64. package/dist/commands/team-agent-readiness.d.ts +18 -2
  65. package/dist/commands/team-agent-readiness.js +39 -39
  66. package/dist/commands/team-agent-readiness.js.map +1 -1
  67. package/dist/commands/team-agents-agents.d.ts +5 -2
  68. package/dist/commands/team-agents-agents.js +152 -15
  69. package/dist/commands/team-agents-agents.js.map +1 -1
  70. package/dist/commands/team-agents-define.d.ts +31 -0
  71. package/dist/commands/team-agents-define.js +176 -0
  72. package/dist/commands/team-agents-define.js.map +1 -0
  73. package/dist/commands/team-agents-mcp.js +112 -10
  74. package/dist/commands/team-agents-mcp.js.map +1 -1
  75. package/dist/commands/team-agents-triggers.d.ts +1 -1
  76. package/dist/commands/team-agents-triggers.js +137 -5
  77. package/dist/commands/team-agents-triggers.js.map +1 -1
  78. package/dist/commands/team-agents.d.ts +4 -1
  79. package/dist/commands/team-agents.js +17 -4
  80. package/dist/commands/team-agents.js.map +1 -1
  81. package/dist/commands/team-llm-key.d.ts +14 -0
  82. package/dist/commands/team-llm-key.js +122 -0
  83. package/dist/commands/team-llm-key.js.map +1 -0
  84. package/dist/commands/teams-audience.d.ts +12 -0
  85. package/dist/commands/teams-audience.js +144 -0
  86. package/dist/commands/teams-audience.js.map +1 -0
  87. package/dist/commands/teams-connect.js +123 -31
  88. package/dist/commands/teams-connect.js.map +1 -1
  89. package/dist/commands/teams-lifecycle.d.ts +90 -0
  90. package/dist/commands/teams-lifecycle.js +457 -0
  91. package/dist/commands/teams-lifecycle.js.map +1 -0
  92. package/dist/commands/teams-onboard.d.ts +14 -0
  93. package/dist/commands/teams-onboard.js +62 -13
  94. package/dist/commands/teams-onboard.js.map +1 -1
  95. package/dist/commands/teams-overview.js +6 -2
  96. package/dist/commands/teams-overview.js.map +1 -1
  97. package/dist/commands/teams-scope.js +4 -0
  98. package/dist/commands/teams-scope.js.map +1 -1
  99. package/dist/commands/teams.d.ts +25 -5
  100. package/dist/commands/teams.js +106 -39
  101. package/dist/commands/teams.js.map +1 -1
  102. package/dist/commands/workflows.d.ts +37 -0
  103. package/dist/commands/workflows.js +589 -0
  104. package/dist/commands/workflows.js.map +1 -0
  105. package/dist/compatibility.d.ts +10 -1
  106. package/dist/compatibility.js +10 -1
  107. package/dist/compatibility.js.map +1 -1
  108. package/dist/connect-fields.d.ts +22 -0
  109. package/dist/connect-fields.js +115 -0
  110. package/dist/connect-fields.js.map +1 -0
  111. package/dist/context.d.ts +12 -0
  112. package/dist/context.js +32 -9
  113. package/dist/context.js.map +1 -1
  114. package/dist/dev-experience.d.ts +125 -0
  115. package/dist/dev-experience.js +128 -0
  116. package/dist/dev-experience.js.map +1 -0
  117. package/dist/experience/boundary.d.ts +12 -0
  118. package/dist/experience/boundary.js +260 -0
  119. package/dist/experience/boundary.js.map +1 -0
  120. package/dist/experience/build.d.ts +16 -0
  121. package/dist/experience/build.js +90 -0
  122. package/dist/experience/build.js.map +1 -0
  123. package/dist/experience/checks.d.ts +29 -0
  124. package/dist/experience/checks.js +133 -0
  125. package/dist/experience/checks.js.map +1 -0
  126. package/dist/experience/contract-sources.d.ts +36 -0
  127. package/dist/experience/contract-sources.js +111 -0
  128. package/dist/experience/contract-sources.js.map +1 -0
  129. package/dist/experience/definition-checks.d.ts +26 -0
  130. package/dist/experience/definition-checks.js +201 -0
  131. package/dist/experience/definition-checks.js.map +1 -0
  132. package/dist/experience/definition-shape.d.ts +60 -0
  133. package/dist/experience/definition-shape.js +2 -0
  134. package/dist/experience/definition-shape.js.map +1 -0
  135. package/dist/experience/init.d.ts +10 -0
  136. package/dist/experience/init.js +64 -0
  137. package/dist/experience/init.js.map +1 -0
  138. package/dist/experience/integrations-codegen.d.ts +17 -0
  139. package/dist/experience/integrations-codegen.js +51 -0
  140. package/dist/experience/integrations-codegen.js.map +1 -0
  141. package/dist/experience/json-schema-to-ts.d.ts +1 -0
  142. package/dist/experience/json-schema-to-ts.js +90 -0
  143. package/dist/experience/json-schema-to-ts.js.map +1 -0
  144. package/dist/experience/load-experience.d.ts +23 -0
  145. package/dist/experience/load-experience.js +115 -0
  146. package/dist/experience/load-experience.js.map +1 -0
  147. package/dist/experience/overrides.d.ts +8 -0
  148. package/dist/experience/overrides.js +21 -0
  149. package/dist/experience/overrides.js.map +1 -0
  150. package/dist/experience/pin-integration.d.ts +8 -0
  151. package/dist/experience/pin-integration.js +17 -0
  152. package/dist/experience/pin-integration.js.map +1 -0
  153. package/dist/experience/pin-ops.d.ts +12 -0
  154. package/dist/experience/pin-ops.js +36 -0
  155. package/dist/experience/pin-ops.js.map +1 -0
  156. package/dist/experience/pins.d.ts +35 -0
  157. package/dist/experience/pins.js +91 -0
  158. package/dist/experience/pins.js.map +1 -0
  159. package/dist/experience/project.d.ts +52 -0
  160. package/dist/experience/project.js +149 -0
  161. package/dist/experience/project.js.map +1 -0
  162. package/dist/experience/publish.d.ts +51 -0
  163. package/dist/experience/publish.js +144 -0
  164. package/dist/experience/publish.js.map +1 -0
  165. package/dist/experience/regenerate.d.ts +10 -0
  166. package/dist/experience/regenerate.js +33 -0
  167. package/dist/experience/regenerate.js.map +1 -0
  168. package/dist/experience/report.d.ts +9 -0
  169. package/dist/experience/report.js +23 -0
  170. package/dist/experience/report.js.map +1 -0
  171. package/dist/harness-scaffold.d.ts +52 -18
  172. package/dist/harness-scaffold.js +189 -9
  173. package/dist/harness-scaffold.js.map +1 -1
  174. package/dist/index.d.ts +13 -0
  175. package/dist/index.js +494 -127
  176. package/dist/index.js.map +1 -1
  177. package/dist/invocation.d.ts +31 -0
  178. package/dist/invocation.js +58 -0
  179. package/dist/invocation.js.map +1 -0
  180. package/dist/project-checks.d.ts +12 -0
  181. package/dist/project-checks.js +46 -0
  182. package/dist/project-checks.js.map +1 -1
  183. package/dist/project.d.ts +14 -0
  184. package/dist/project.js +10 -0
  185. package/dist/project.js.map +1 -1
  186. package/dist/repo/publish.d.ts +42 -0
  187. package/dist/repo/publish.js +225 -0
  188. package/dist/repo/publish.js.map +1 -0
  189. package/dist/repo/scaffold.d.ts +30 -0
  190. package/dist/repo/scaffold.js +165 -0
  191. package/dist/repo/scaffold.js.map +1 -0
  192. package/dist/runs-api.js +8 -3
  193. package/dist/runs-api.js.map +1 -1
  194. package/dist/safe-fs.d.ts +18 -0
  195. package/dist/safe-fs.js +57 -0
  196. package/dist/safe-fs.js.map +1 -1
  197. package/dist/secret-form.d.ts +48 -0
  198. package/dist/secret-form.js +212 -0
  199. package/dist/secret-form.js.map +1 -0
  200. package/dist/secret-input.d.ts +96 -0
  201. package/dist/secret-input.js +299 -0
  202. package/dist/secret-input.js.map +1 -0
  203. package/dist/team-connect-api.d.ts +78 -3
  204. package/dist/team-connect-api.js +17 -2
  205. package/dist/team-connect-api.js.map +1 -1
  206. package/dist/team-lifecycle-api.d.ts +435 -0
  207. package/dist/team-lifecycle-api.js +301 -0
  208. package/dist/team-lifecycle-api.js.map +1 -0
  209. package/dist/teams-api.d.ts +49 -1
  210. package/dist/teams-api.js +149 -27
  211. package/dist/teams-api.js.map +1 -1
  212. package/dist/unknown-command.d.ts +18 -0
  213. package/dist/unknown-command.js +50 -0
  214. package/dist/unknown-command.js.map +1 -0
  215. package/dist/validate-findings.js +2 -1
  216. package/dist/validate-findings.js.map +1 -1
  217. package/dist/workflows-api.d.ts +69 -0
  218. package/dist/workflows-api.js +182 -0
  219. package/dist/workflows-api.js.map +1 -0
  220. package/package.json +3 -3
  221. package/templates/AGENTS.md.tmpl +6 -4
  222. package/templates/claude-skill.md.tmpl +4 -1
  223. package/templates/ekanos.json.tmpl +1 -0
  224. package/templates/experience/AGENTS.md.tmpl +22 -0
  225. package/templates/experience/ekanos.json.tmpl +7 -0
  226. package/templates/experience/ekanos.lock.json.tmpl +4 -0
  227. package/templates/experience/eslint.config.mjs.tmpl +25 -0
  228. package/templates/experience/gitignore.tmpl +17 -0
  229. package/templates/experience/package.json.tmpl +41 -0
  230. package/templates/experience/src/.ekanos/integrations.d.ts.tmpl +3 -0
  231. package/templates/experience/src/experience.ts.tmpl +30 -0
  232. package/templates/experience/src/widgets/hello-widget.tsx.tmpl +40 -0
  233. package/templates/experience/tsconfig.json.tmpl +20 -0
  234. package/templates/harness/app/%5F%5Fekanos/api/[...path]/route.ts.tmpl +9 -0
  235. package/templates/harness/app/[slug]/activation/page.tsx.tmpl +1 -1
  236. package/templates/harness/app/[slug]/page.tsx.tmpl +1 -1
  237. package/templates/harness/app/[slug]/tile/page.tsx.tmpl +1 -1
  238. package/templates/harness/app/[slug]/triggers/page.tsx.tmpl +1 -1
  239. package/templates/harness/app/[slug]/widgets/[widgetId]/page.tsx.tmpl +1 -1
  240. package/templates/harness/app/[slug]/widgets/page.tsx.tmpl +1 -1
  241. package/templates/harness/app/experience/layout.tsx.tmpl +17 -0
  242. package/templates/harness/app/experience/page.tsx.tmpl +1 -0
  243. package/templates/harness/app/experience/pages/[id]/page.tsx.tmpl +1 -0
  244. package/templates/harness/app/experience/review-queue/page.tsx.tmpl +1 -0
  245. package/templates/harness/app/experience/runs/page.tsx.tmpl +1 -0
  246. package/templates/harness/app/experience/widgets/[id]/page.tsx.tmpl +1 -0
  247. package/templates/harness/app/experience/widgets/page.tsx.tmpl +1 -0
  248. package/templates/harness/app/experience/workflows/[id]/page.tsx.tmpl +1 -0
  249. package/templates/harness/app/experience/workflows/page.tsx.tmpl +1 -0
  250. package/templates/harness/app/integrations/[slug]/connect/page.tsx.tmpl +1 -0
  251. package/templates/harness/app/integrations/[slug]/events/page.tsx.tmpl +1 -0
  252. package/templates/harness/app/integrations/[slug]/health/page.tsx.tmpl +1 -0
  253. package/templates/harness/app/integrations/[slug]/operations/[kind]/[name]/page.tsx.tmpl +1 -0
  254. package/templates/harness/app/integrations/[slug]/operations/page.tsx.tmpl +1 -0
  255. package/templates/harness/app/integrations/[slug]/page.tsx.tmpl +1 -0
  256. package/templates/harness/app/integrations/[slug]/preview/activation/page.tsx.tmpl +1 -0
  257. package/templates/harness/app/integrations/[slug]/preview/layout.tsx.tmpl +1 -0
  258. package/templates/harness/app/integrations/[slug]/preview/page.tsx.tmpl +1 -0
  259. package/templates/harness/app/integrations/[slug]/preview/tile/page.tsx.tmpl +1 -0
  260. package/templates/harness/app/integrations/[slug]/preview/triggers/page.tsx.tmpl +1 -0
  261. package/templates/harness/app/integrations/[slug]/preview/widgets/[widgetId]/page.tsx.tmpl +1 -0
  262. package/templates/harness/app/integrations/[slug]/preview/widgets/page.tsx.tmpl +1 -0
  263. package/templates/harness/app/integrations/[slug]/runs/page.tsx.tmpl +1 -0
  264. package/templates/harness/app/integrations/layout.tsx.tmpl +1 -0
  265. package/templates/harness/app/integrations/page.tsx.tmpl +1 -0
  266. package/templates/harness/app/page.experience.tsx.tmpl +5 -0
  267. package/templates/harness/repo/app/%5F%5Fekanos/api/[...path]/route.ts.tmpl +11 -0
  268. package/templates/harness/repo/app/(repo)/connections/page.tsx.tmpl +1 -0
  269. package/templates/harness/repo/app/(repo)/layout.tsx.tmpl +1 -0
  270. package/templates/harness/repo/app/(repo)/page.tsx.tmpl +1 -0
  271. package/templates/harness/repo/app/experiences/[name]/connect/page.tsx.tmpl +1 -0
  272. package/templates/harness/repo/app/experiences/[name]/layout.tsx.tmpl +9 -0
  273. package/templates/harness/repo/app/experiences/page.tsx.tmpl +5 -0
  274. package/templates/harness/repo/app/harness-shell.tsx.tmpl +9 -0
  275. package/templates/harness/repo/app/integrations/[slug]/layout.tsx.tmpl +1 -0
  276. package/templates/harness/repo/app/integrations/page.tsx.tmpl +5 -0
  277. package/templates/harness/repo/app/repo-experiences.ts.tmpl +5 -0
  278. package/templates/harness/styles/globals.css.tmpl +15 -1
  279. package/templates/package.json.tmpl +4 -4
  280. package/templates/skills/build-agent/SKILL.md +43 -10
  281. package/templates/skills/build-agent/references/agent-json.md +4 -1
  282. package/templates/skills/build-agent/references/app-setup.md +14 -7
  283. package/templates/skills/build-agent/references/rollout.md +26 -2
  284. package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
  285. package/templates/skills/build-integration/references/widget-design.md +1 -1
  286. package/templates/skills/ekanos-platform/SKILL.md +66 -14
  287. package/templates/skills/polish-widgets/references/patterns.md +3 -3
@@ -10,8 +10,10 @@ export interface CatalogArgs {
10
10
  }
11
11
  /**
12
12
  * `catalog` — what the Source can already do (plan 239.0). Lists every
13
- * product the Source can use, with its tools, agent events and the steps
14
- * left to set it up; `ekanos catalog <product>` shows one in full.
13
+ * product the Source can use, Experiences then Integrations as `ekanos
14
+ * sources products` splits them, with its tools, agent events and the steps
15
+ * left to set it up; `ekanos catalog <product>` shows one in full, with each
16
+ * tool's inputs and whose connection an agent run uses.
15
17
  *
16
18
  * Read before building: an agent migration asks it first, so a capability
17
19
  * the Source already has is set up rather than rebuilt. Works outside a
@@ -7,8 +7,10 @@ import { pluralize } from '../ui.js';
7
7
  import { withDocsHint } from './agents-init.js';
8
8
  /**
9
9
  * `catalog` — what the Source can already do (plan 239.0). Lists every
10
- * product the Source can use, with its tools, agent events and the steps
11
- * left to set it up; `ekanos catalog <product>` shows one in full.
10
+ * product the Source can use, Experiences then Integrations as `ekanos
11
+ * sources products` splits them, with its tools, agent events and the steps
12
+ * left to set it up; `ekanos catalog <product>` shows one in full, with each
13
+ * tool's inputs and whose connection an agent run uses.
12
14
  *
13
15
  * Read before building: an agent migration asks it first, so a capability
14
16
  * the Source already has is set up rather than rebuilt. Works outside a
@@ -29,42 +31,70 @@ export async function runCatalog(ctx, args) {
29
31
  result = await fetchSourceCatalog(env.host, session.accessToken, query);
30
32
  }
31
33
  const catalog = requireCatalog(result, env);
32
- return ctx.succeed(Object.assign({ host: env.host }, catalog), withDocsHint(ctx.ui, args.dir, args.product
34
+ // The agent-design tip belongs on the overview only, not every product.
35
+ return ctx.succeed(Object.assign({ host: env.host }, catalog), args.product
33
36
  ? productDetail(ctx.ui, catalog.products[0])
34
- : catalogSummary(ctx.ui, catalog)));
37
+ : withDocsHint(ctx.ui, args.dir, catalogSummary(ctx.ui, catalog)));
35
38
  }
36
39
  function requireCatalog(result, env) {
37
40
  if (result.status === 'ok')
38
41
  return result.catalog;
39
42
  throw authRequiredError(`The session for ${env.host} could not authorize the catalog read.`, loginHint(env));
40
43
  }
41
- const AVAILABILITY_LABEL = {
44
+ const STATUS_LABEL = {
42
45
  enabled: 'Enabled on this Source',
43
- 'turned-off': 'Not enabled — granted, but switched off',
44
- available: 'Not enabled — only a super-admin enables it',
46
+ 'turned-off': 'Not enabled — granted, but a Flag or plan switches it off',
47
+ available: 'Not enabled',
48
+ };
49
+ const SHORT_STATUS = {
50
+ enabled: '✓ enabled',
51
+ 'turned-off': '✗ switched off',
52
+ available: '✗ not enabled',
53
+ };
54
+ /** Who does a setup step, in words. The wire value `ekanos` is Vastly. */
55
+ const ACTOR_LABEL = {
56
+ ekanos: 'Vastly',
57
+ source_admin: 'Source admin',
58
+ team: 'team',
59
+ };
60
+ /** A `team` step on a per-person product is each person's to do. */
61
+ function actorLabel(actor, product) {
62
+ return actor === 'team' && product.scope === 'user'
63
+ ? 'each person'
64
+ : ACTOR_LABEL[actor];
65
+ }
66
+ const KIND_TITLE = {
67
+ experience: 'Experiences',
68
+ integration: 'Integrations',
45
69
  };
46
70
  function catalogSummary(ui, catalog) {
47
- const blocks = ['enabled', 'turned-off', 'available']
48
- .map((availability) => {
49
- const products = catalog.products.filter((product) => product.availability === availability);
50
- if (products.length === 0)
51
- return null;
71
+ // The same split as `ekanos sources products`: Experiences, then Integrations.
72
+ const blocks = ['experience', 'integration'].map((kind) => {
73
+ const products = catalog.products.filter((product) => product.kind === kind);
52
74
  return ui.result({
53
- title: `${AVAILABILITY_LABEL[availability]} (${products.length})`,
54
- tone: availability === 'enabled' ? 'ok' : 'warn',
75
+ title: `${KIND_TITLE[kind]} on ${catalog.source.slug} (${products.length})`,
76
+ tone: 'ok',
55
77
  rows: products.map((product) => [
56
78
  product.slug,
57
- [product.name, describeShape(product), openSteps(product)]
79
+ [
80
+ SHORT_STATUS[product.availability],
81
+ product.name,
82
+ describeShape(product),
83
+ nextStep(product),
84
+ ]
58
85
  .filter(Boolean)
59
86
  .join(' · '),
60
87
  ]),
61
88
  });
62
- })
63
- .filter((block) => block !== null);
89
+ });
90
+ const unregistered = catalog.products.filter((product) => product.registered === false).length;
64
91
  return [
65
92
  ...blocks,
66
- ui.hint(`${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}. ` +
67
- `"ekanos catalog <product>" shows tools, agent events and setup steps.`),
93
+ ui.hint(`${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}` +
94
+ (unregistered > 0
95
+ ? `, ${unregistered} with no package on this host (listed so this matches "ekanos sources products"; nothing here can use them)`
96
+ : '') +
97
+ `. "ekanos catalog <product>" shows tools with their inputs, whose connection agent runs use, agent events and setup steps.`),
68
98
  ].join('\n\n');
69
99
  }
70
100
  function productDetail(ui, product) {
@@ -75,16 +105,31 @@ function productDetail(ui, product) {
75
105
  'Kind',
76
106
  product.kind === 'experience' ? 'Ekanos Experience' : 'Integration',
77
107
  ],
78
- ['Status', AVAILABILITY_LABEL[product.availability]],
108
+ [
109
+ 'Status',
110
+ [STATUS_LABEL[product.availability], enableNeeds(product)]
111
+ .filter(Boolean)
112
+ .join(' — '),
113
+ ],
79
114
  ];
115
+ if (product.registered === false) {
116
+ rows.push([
117
+ 'Package',
118
+ 'None on this host — nothing here can use it until a build that ships it is deployed.',
119
+ ]);
120
+ }
121
+ if (product.connection) {
122
+ rows.push(['Connections', describeConnection(product.connection)]);
123
+ }
80
124
  if (product.connectedTeams !== null) {
81
125
  rows.push(['Teams connected', String(product.connectedTeams)]);
82
126
  }
127
+ if (product.connectedPeople !== null &&
128
+ product.connectedPeople !== undefined) {
129
+ rows.push(['People connected', String(product.connectedPeople)]);
130
+ }
83
131
  if (product.tools.length > 0) {
84
- rows.push([
85
- 'Tools',
86
- product.tools.map((tool) => `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})`),
87
- ]);
132
+ rows.push(['Tools', product.tools.flatMap(describeTool)]);
88
133
  }
89
134
  if (product.agentEvents.length > 0) {
90
135
  rows.push([
@@ -95,18 +140,22 @@ function productDetail(ui, product) {
95
140
  if (product.agentReplyTool) {
96
141
  rows.push(['Replies with', product.agentReplyTool]);
97
142
  }
98
- rows.push([
99
- 'Setup',
100
- product.setupSteps.flatMap((step, index) => { var _a; return [
101
- `${index + 1}. [${step.state}] ${step.title} (${step.actor}) — ${step.detail}` +
102
- (step.guideUrl ? ` ${step.guideUrl}` : ''),
103
- ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),
104
- ...((_a = step.instructions) !== null && _a !== void 0 ? _a : []).map((line, lineIndex) => ` ${String.fromCharCode(97 + lineIndex)}. ${line}`),
105
- ]; }),
106
- ]);
143
+ if (product.setupSteps.length > 0) {
144
+ rows.push([
145
+ 'Setup',
146
+ product.setupSteps.flatMap((step, index) => { var _a; return [
147
+ `${index + 1}. [${step.state}] ${step.title} (${actorLabel(step.actor, product)}) — ${step.detail}` +
148
+ (step.guideUrl ? ` ${step.guideUrl}` : ''),
149
+ ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),
150
+ ...((_a = step.instructions) !== null && _a !== void 0 ? _a : []).map((line, lineIndex) => ` ${String.fromCharCode(97 + lineIndex)}. ${line}`),
151
+ ]; }),
152
+ ]);
153
+ }
107
154
  return ui.result({ title: `${product.name} (${product.slug})`, rows });
108
155
  }
109
156
  function describeShape(product) {
157
+ if (product.registered === false)
158
+ return 'no package on this host';
110
159
  const parts = [
111
160
  product.tools.length > 0 ? pluralize(product.tools.length, 'tool') : null,
112
161
  product.agentEvents.length > 0
@@ -115,8 +164,90 @@ function describeShape(product) {
115
164
  ].filter(Boolean);
116
165
  return parts.join(', ');
117
166
  }
118
- function openSteps(product) {
167
+ /**
168
+ * What stands between the Source and using it. A product only Vastly can
169
+ * enable says so instead of counting steps nobody on the Source can take.
170
+ */
171
+ function nextStep(product) {
172
+ if (product.registered === false)
173
+ return '';
174
+ const needs = enableNeeds(product);
175
+ if (needs)
176
+ return needs;
119
177
  const open = product.setupSteps.filter((step) => step.state === 'todo');
120
- return open.length === 0 ? '' : `${pluralize(open.length, 'step')} left`;
178
+ const ours = open.filter((step) => step.actor !== 'ekanos');
179
+ return [
180
+ ours.length > 0 ? `${pluralize(ours.length, 'step')} left` : null,
181
+ ours.length < open.length ? 'waiting on Vastly' : null,
182
+ ]
183
+ .filter(Boolean)
184
+ .join(', ');
185
+ }
186
+ /** Who has to enable a product that is not enabled, or null when it is. */
187
+ function enableNeeds(product) {
188
+ if (product.availability === 'enabled')
189
+ return null;
190
+ if (product.availability === 'turned-off') {
191
+ return 'needs Vastly to switch it on';
192
+ }
193
+ return product.owned
194
+ ? `built by this Source — its Source admin enables it ("ekanos sources products enable ${product.slug}")`
195
+ : 'needs a Vastly grant';
196
+ }
197
+ /**
198
+ * Whose connection a product's calls use: the team's, each person's own (on a
199
+ * team or provided agent, the creator's, lent to whoever the run acts for),
200
+ * or the Source's, when a Source admin connected it once for every team.
201
+ */
202
+ function describeConnection(connection) {
203
+ const lines = [];
204
+ switch (connection.connectedBy) {
205
+ case 'nobody':
206
+ return ['Nothing to connect — it works as shipped.'];
207
+ case 'team':
208
+ lines.push("Each team connects its own. An agent run uses its team's connection.");
209
+ break;
210
+ case 'person':
211
+ lines.push("Each person connects their own. An agent run uses its creator's own connection — on a personal agent that is the person it runs for, including its schedule and webhook runs; on a team or provided agent it is lent to whoever the run acts for.");
212
+ break;
213
+ }
214
+ if (connection.sourceConnection !== 'unsupported') {
215
+ lines.push(`A Source admin can connect it once for every team ("ekanos apps connect"): a provided agent whose template marks it Source-owned then uses the Source's connection, limited to the team's routed records. ` +
216
+ (connection.sourceConnection === 'connected'
217
+ ? 'This Source has.'
218
+ : 'This Source has not yet.'));
219
+ }
220
+ return lines;
221
+ }
222
+ /**
223
+ * A tool, then its inputs one per line from its JSON schema — what an agent
224
+ * designer needs to see which other tool supplies an id.
225
+ */
226
+ function describeTool(tool) {
227
+ const head = `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})` +
228
+ (tool.description ? ` — ${tool.description}` : '');
229
+ if (!tool.inputSchema)
230
+ return [head];
231
+ const properties = asRecord(tool.inputSchema.properties);
232
+ const required = new Set(Array.isArray(tool.inputSchema.required)
233
+ ? tool.inputSchema.required.filter((key) => typeof key === 'string')
234
+ : []);
235
+ const inputs = Object.entries(properties).map(([key, value]) => {
236
+ const property = asRecord(value);
237
+ const type = typeof property.type === 'string' ? property.type : null;
238
+ const description = typeof property.description === 'string' ? property.description : null;
239
+ return (` ${key}` +
240
+ [type, required.has(key) ? 'required' : null]
241
+ .filter(Boolean)
242
+ .map((part, index) => (index === 0 ? `: ${part}` : `, ${part}`))
243
+ .join('') +
244
+ (description ? ` — ${description}` : ''));
245
+ });
246
+ return [head, ...(inputs.length > 0 ? inputs : [' no inputs'])];
247
+ }
248
+ function asRecord(value) {
249
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
250
+ ? value
251
+ : {};
121
252
  }
122
253
  //# sourceMappingURL=catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CatalogProduct, SourceCatalog } from '@ekanos/integration-schema';\n\nimport { loginHint } from '../auth/host-trust';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type FetchSourceCatalogResult,\n fetchSourceCatalog,\n} from '../catalog-api';\nimport type { CliContext } from '../context';\nimport { authRequiredError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport { type Ui, pluralize } from '../ui';\nimport { withDocsHint } from './agents-init';\n\nexport interface CatalogArgs {\n host?: string;\n source?: string;\n /** One product's detail, when given. */\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `catalog` — what the Source can already do (plan 239.0). Lists every\n * product the Source can use, with its tools, agent events and the steps\n * left to set it up; `ekanos catalog <product>` shows one in full.\n *\n * Read before building: an agent migration asks it first, so a capability\n * the Source already has is set up rather than rebuilt. Works outside a\n * project — the Source comes from `--source`, else `ekanos.json`, else the\n * caller's only seat.\n */\nexport async function runCatalog(\n ctx: CliContext,\n args: CatalogArgs,\n): Promise<ExitCode> {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n let session = requireSession(env);\n\n const resolved = await resolveSourceTarget(env, session, args);\n session = resolved.session;\n\n const query = { source: resolved.source, product: args.product };\n let result = await fetchSourceCatalog(env.host, session.accessToken, query);\n if (result.status === 'unauthorized') {\n session = await refreshStoredSession(env, session);\n result = await fetchSourceCatalog(env.host, session.accessToken, query);\n }\n const catalog = requireCatalog(result, env);\n\n return ctx.succeed(\n { host: env.host, ...catalog },\n withDocsHint(\n ctx.ui,\n args.dir,\n args.product\n ? productDetail(ctx.ui, catalog.products[0]!)\n : catalogSummary(ctx.ui, catalog),\n ),\n );\n}\n\nfunction requireCatalog(\n result: FetchSourceCatalogResult,\n env: AuthEnvironment,\n): SourceCatalog {\n if (result.status === 'ok') return result.catalog;\n throw authRequiredError(\n `The session for ${env.host} could not authorize the catalog read.`,\n loginHint(env),\n );\n}\n\nconst AVAILABILITY_LABEL = {\n enabled: 'Enabled on this Source',\n 'turned-off': 'Not enabled — granted, but switched off',\n available: 'Not enabled — only a super-admin enables it',\n} as const;\n\nfunction catalogSummary(ui: Ui, catalog: SourceCatalog): string {\n const blocks = (['enabled', 'turned-off', 'available'] as const)\n .map((availability) => {\n const products = catalog.products.filter(\n (product) => product.availability === availability,\n );\n if (products.length === 0) return null;\n return ui.result({\n title: `${AVAILABILITY_LABEL[availability]} (${products.length})`,\n tone: availability === 'enabled' ? 'ok' : 'warn',\n rows: products.map((product): [string, string] => [\n product.slug,\n [product.name, describeShape(product), openSteps(product)]\n .filter(Boolean)\n .join(' · '),\n ]),\n });\n })\n .filter((block): block is string => block !== null);\n\n return [\n ...blocks,\n ui.hint(\n `${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}. ` +\n `\"ekanos catalog <product>\" shows tools, agent events and setup steps.`,\n ),\n ].join('\\n\\n');\n}\n\nfunction productDetail(ui: Ui, product: CatalogProduct): string {\n const rows: [string, string | string[]][] = [\n ['What', product.summary ?? '—'],\n [\n 'Kind',\n product.kind === 'experience' ? 'Ekanos Experience' : 'Integration',\n ],\n ['Status', AVAILABILITY_LABEL[product.availability]],\n ];\n if (product.connectedTeams !== null) {\n rows.push(['Teams connected', String(product.connectedTeams)]);\n }\n if (product.tools.length > 0) {\n rows.push([\n 'Tools',\n product.tools.map(\n (tool) =>\n `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})`,\n ),\n ]);\n }\n if (product.agentEvents.length > 0) {\n rows.push([\n 'Agent triggers',\n product.agentEvents.map((event) => `${event.id} — ${event.label}`),\n ]);\n }\n if (product.agentReplyTool) {\n rows.push(['Replies with', product.agentReplyTool]);\n }\n rows.push([\n 'Setup',\n product.setupSteps.flatMap((step, index) => [\n `${index + 1}. [${step.state}] ${step.title} (${step.actor}) — ${step.detail}` +\n (step.guideUrl ? ` ${step.guideUrl}` : ''),\n ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),\n ...(step.instructions ?? []).map(\n (line, lineIndex) =>\n ` ${String.fromCharCode(97 + lineIndex)}. ${line}`,\n ),\n ]),\n ]);\n\n return ui.result({ title: `${product.name} (${product.slug})`, rows });\n}\n\nfunction describeShape(product: CatalogProduct): string {\n const parts = [\n product.tools.length > 0 ? pluralize(product.tools.length, 'tool') : null,\n product.agentEvents.length > 0\n ? pluralize(product.agentEvents.length, 'agent trigger')\n : null,\n ].filter(Boolean);\n return parts.join(', ');\n}\n\nfunction openSteps(product: CatalogProduct): string {\n const open = product.setupSteps.filter((step) => step.state === 'todo');\n return open.length === 0 ? '' : `${pluralize(open.length, 'step')} left`;\n}\n"]}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CatalogConnection,\n CatalogProduct,\n CatalogSetupStep,\n CatalogTool,\n SourceCatalog,\n} from '@ekanos/integration-schema';\n\nimport { loginHint } from '../auth/host-trust';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type FetchSourceCatalogResult,\n fetchSourceCatalog,\n} from '../catalog-api';\nimport type { CliContext } from '../context';\nimport { authRequiredError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport { type Ui, pluralize } from '../ui';\nimport { withDocsHint } from './agents-init';\n\nexport interface CatalogArgs {\n host?: string;\n source?: string;\n /** One product's detail, when given. */\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `catalog` — what the Source can already do (plan 239.0). Lists every\n * product the Source can use, Experiences then Integrations as `ekanos\n * sources products` splits them, with its tools, agent events and the steps\n * left to set it up; `ekanos catalog <product>` shows one in full, with each\n * tool's inputs and whose connection an agent run uses.\n *\n * Read before building: an agent migration asks it first, so a capability\n * the Source already has is set up rather than rebuilt. Works outside a\n * project — the Source comes from `--source`, else `ekanos.json`, else the\n * caller's only seat.\n */\nexport async function runCatalog(\n ctx: CliContext,\n args: CatalogArgs,\n): Promise<ExitCode> {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n let session = requireSession(env);\n\n const resolved = await resolveSourceTarget(env, session, args);\n session = resolved.session;\n\n const query = { source: resolved.source, product: args.product };\n let result = await fetchSourceCatalog(env.host, session.accessToken, query);\n if (result.status === 'unauthorized') {\n session = await refreshStoredSession(env, session);\n result = await fetchSourceCatalog(env.host, session.accessToken, query);\n }\n const catalog = requireCatalog(result, env);\n\n // The agent-design tip belongs on the overview only, not every product.\n return ctx.succeed(\n { host: env.host, ...catalog },\n args.product\n ? productDetail(ctx.ui, catalog.products[0]!)\n : withDocsHint(ctx.ui, args.dir, catalogSummary(ctx.ui, catalog)),\n );\n}\n\nfunction requireCatalog(\n result: FetchSourceCatalogResult,\n env: AuthEnvironment,\n): SourceCatalog {\n if (result.status === 'ok') return result.catalog;\n throw authRequiredError(\n `The session for ${env.host} could not authorize the catalog read.`,\n loginHint(env),\n );\n}\n\nconst STATUS_LABEL = {\n enabled: 'Enabled on this Source',\n 'turned-off': 'Not enabled — granted, but a Flag or plan switches it off',\n available: 'Not enabled',\n} as const;\n\nconst SHORT_STATUS = {\n enabled: '✓ enabled',\n 'turned-off': '✗ switched off',\n available: '✗ not enabled',\n} as const;\n\n/** Who does a setup step, in words. The wire value `ekanos` is Vastly. */\nconst ACTOR_LABEL = {\n ekanos: 'Vastly',\n source_admin: 'Source admin',\n team: 'team',\n} as const;\n\n/** A `team` step on a per-person product is each person's to do. */\nfunction actorLabel(\n actor: CatalogSetupStep['actor'],\n product: CatalogProduct,\n): string {\n return actor === 'team' && product.scope === 'user'\n ? 'each person'\n : ACTOR_LABEL[actor];\n}\n\nconst KIND_TITLE = {\n experience: 'Experiences',\n integration: 'Integrations',\n} as const;\n\nfunction catalogSummary(ui: Ui, catalog: SourceCatalog): string {\n // The same split as `ekanos sources products`: Experiences, then Integrations.\n const blocks = (['experience', 'integration'] as const).map((kind) => {\n const products = catalog.products.filter(\n (product) => product.kind === kind,\n );\n return ui.result({\n title: `${KIND_TITLE[kind]} on ${catalog.source.slug} (${products.length})`,\n tone: 'ok',\n rows: products.map((product): [string, string] => [\n product.slug,\n [\n SHORT_STATUS[product.availability],\n product.name,\n describeShape(product),\n nextStep(product),\n ]\n .filter(Boolean)\n .join(' · '),\n ]),\n });\n });\n\n const unregistered = catalog.products.filter(\n (product) => product.registered === false,\n ).length;\n return [\n ...blocks,\n ui.hint(\n `${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}` +\n (unregistered > 0\n ? `, ${unregistered} with no package on this host (listed so this matches \"ekanos sources products\"; nothing here can use them)`\n : '') +\n `. \"ekanos catalog <product>\" shows tools with their inputs, whose connection agent runs use, agent events and setup steps.`,\n ),\n ].join('\\n\\n');\n}\n\nfunction productDetail(ui: Ui, product: CatalogProduct): string {\n const rows: [string, string | string[]][] = [\n ['What', product.summary ?? '—'],\n [\n 'Kind',\n product.kind === 'experience' ? 'Ekanos Experience' : 'Integration',\n ],\n [\n 'Status',\n [STATUS_LABEL[product.availability], enableNeeds(product)]\n .filter(Boolean)\n .join(' — '),\n ],\n ];\n if (product.registered === false) {\n rows.push([\n 'Package',\n 'None on this host — nothing here can use it until a build that ships it is deployed.',\n ]);\n }\n if (product.connection) {\n rows.push(['Connections', describeConnection(product.connection)]);\n }\n if (product.connectedTeams !== null) {\n rows.push(['Teams connected', String(product.connectedTeams)]);\n }\n if (\n product.connectedPeople !== null &&\n product.connectedPeople !== undefined\n ) {\n rows.push(['People connected', String(product.connectedPeople)]);\n }\n if (product.tools.length > 0) {\n rows.push(['Tools', product.tools.flatMap(describeTool)]);\n }\n if (product.agentEvents.length > 0) {\n rows.push([\n 'Agent triggers',\n product.agentEvents.map((event) => `${event.id} — ${event.label}`),\n ]);\n }\n if (product.agentReplyTool) {\n rows.push(['Replies with', product.agentReplyTool]);\n }\n if (product.setupSteps.length > 0) {\n rows.push([\n 'Setup',\n product.setupSteps.flatMap((step, index) => [\n `${index + 1}. [${step.state}] ${step.title} (${actorLabel(step.actor, product)}) — ${step.detail}` +\n (step.guideUrl ? ` ${step.guideUrl}` : ''),\n ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),\n ...(step.instructions ?? []).map(\n (line, lineIndex) =>\n ` ${String.fromCharCode(97 + lineIndex)}. ${line}`,\n ),\n ]),\n ]);\n }\n\n return ui.result({ title: `${product.name} (${product.slug})`, rows });\n}\n\nfunction describeShape(product: CatalogProduct): string {\n if (product.registered === false) return 'no package on this host';\n const parts = [\n product.tools.length > 0 ? pluralize(product.tools.length, 'tool') : null,\n product.agentEvents.length > 0\n ? pluralize(product.agentEvents.length, 'agent trigger')\n : null,\n ].filter(Boolean);\n return parts.join(', ');\n}\n\n/**\n * What stands between the Source and using it. A product only Vastly can\n * enable says so instead of counting steps nobody on the Source can take.\n */\nfunction nextStep(product: CatalogProduct): string {\n if (product.registered === false) return '';\n const needs = enableNeeds(product);\n if (needs) return needs;\n\n const open = product.setupSteps.filter((step) => step.state === 'todo');\n const ours = open.filter((step) => step.actor !== 'ekanos');\n return [\n ours.length > 0 ? `${pluralize(ours.length, 'step')} left` : null,\n ours.length < open.length ? 'waiting on Vastly' : null,\n ]\n .filter(Boolean)\n .join(', ');\n}\n\n/** Who has to enable a product that is not enabled, or null when it is. */\nfunction enableNeeds(product: CatalogProduct): string | null {\n if (product.availability === 'enabled') return null;\n if (product.availability === 'turned-off') {\n return 'needs Vastly to switch it on';\n }\n return product.owned\n ? `built by this Source — its Source admin enables it (\"ekanos sources products enable ${product.slug}\")`\n : 'needs a Vastly grant';\n}\n\n/**\n * Whose connection a product's calls use: the team's, each person's own (on a\n * team or provided agent, the creator's, lent to whoever the run acts for),\n * or the Source's, when a Source admin connected it once for every team.\n */\nfunction describeConnection(connection: CatalogConnection): string[] {\n const lines: string[] = [];\n switch (connection.connectedBy) {\n case 'nobody':\n return ['Nothing to connect — it works as shipped.'];\n case 'team':\n lines.push(\n \"Each team connects its own. An agent run uses its team's connection.\",\n );\n break;\n case 'person':\n lines.push(\n \"Each person connects their own. An agent run uses its creator's own connection — on a personal agent that is the person it runs for, including its schedule and webhook runs; on a team or provided agent it is lent to whoever the run acts for.\",\n );\n break;\n }\n if (connection.sourceConnection !== 'unsupported') {\n lines.push(\n `A Source admin can connect it once for every team (\"ekanos apps connect\"): a provided agent whose template marks it Source-owned then uses the Source's connection, limited to the team's routed records. ` +\n (connection.sourceConnection === 'connected'\n ? 'This Source has.'\n : 'This Source has not yet.'),\n );\n }\n return lines;\n}\n\n/**\n * A tool, then its inputs one per line from its JSON schema — what an agent\n * designer needs to see which other tool supplies an id.\n */\nfunction describeTool(tool: CatalogTool): string[] {\n const head =\n `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})` +\n (tool.description ? ` — ${tool.description}` : '');\n if (!tool.inputSchema) return [head];\n\n const properties = asRecord(tool.inputSchema.properties);\n const required = new Set(\n Array.isArray(tool.inputSchema.required)\n ? tool.inputSchema.required.filter(\n (key): key is string => typeof key === 'string',\n )\n : [],\n );\n const inputs = Object.entries(properties).map(([key, value]) => {\n const property = asRecord(value);\n const type = typeof property.type === 'string' ? property.type : null;\n const description =\n typeof property.description === 'string' ? property.description : null;\n return (\n ` ${key}` +\n [type, required.has(key) ? 'required' : null]\n .filter(Boolean)\n .map((part, index) => (index === 0 ? `: ${part}` : `, ${part}`))\n .join('') +\n (description ? ` — ${description}` : '')\n );\n });\n return [head, ...(inputs.length > 0 ? inputs : [' no inputs'])];\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { ExperienceCommand } from './index-experience.js';
2
+ export declare const checkCommand: ExperienceCommand;
@@ -0,0 +1,43 @@
1
+ import { harnessPinsResolver } from '../dev-experience.js';
2
+ import { runExperienceChecks } from '../experience/checks.js';
3
+ import { readExperienceProject } from '../experience/project.js';
4
+ import { failOnErrors } from '../experience/report.js';
5
+ export const checkCommand = {
6
+ name: 'check',
7
+ usage: [
8
+ ' check Run the experience gate: integration pins, generated types, integration-',
9
+ ' import boundary (source + bundle), fixtures, definition, typecheck',
10
+ ],
11
+ specs: {
12
+ dir: {
13
+ type: 'string',
14
+ description: 'Project directory (default: the current one)',
15
+ },
16
+ typecheck: {
17
+ type: 'boolean',
18
+ default: true,
19
+ description: 'Run tsc over the project (--no-typecheck skips)',
20
+ },
21
+ },
22
+ async run(ctx, args) {
23
+ const project = readExperienceProject(args.dir);
24
+ const result = await runExperienceChecks(project, {
25
+ typecheck: args.flags.typecheck !== false,
26
+ loadDefinition: true,
27
+ inlineSdk: args.env.EKANOS_INLINE_SDK,
28
+ pinsResolver: await harnessPinsResolver(project.dir, args.env),
29
+ });
30
+ const failed = failOnErrors(ctx, 'check', result.findings, {
31
+ slug: project.slug,
32
+ integrations: project.integrations.map((u) => u.name),
33
+ }, project.dir);
34
+ if (failed !== null)
35
+ return failed;
36
+ return ctx.succeed({
37
+ slug: project.slug,
38
+ integrations: project.integrations.map((u) => u.name),
39
+ findings: result.findings,
40
+ }, `check: OK - ${project.slug} (${project.integrations.length} integration${project.integrations.length === 1 ? '' : 's'})${result.findings.length ? `, ${result.findings.length} warning${result.findings.length === 1 ? '' : 's'}` : ''}.`);
41
+ },
42
+ };
43
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,IAAI,EAAE,OAAO;IACb,KAAK,EAAE;QACL,uFAAuF;QACvF,iFAAiF;KAClF;IACD,KAAK,EAAE;QACL,GAAG,EAAE;YACH,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,8CAA8C;SAC5D;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,iDAAiD;SAC/D;KACF;IACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;QACjB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE;YAChD,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,KAAK;YACzC,cAAc,EAAE,IAAI;YACpB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB;YACrC,YAAY,EAAE,MAAM,mBAAmB,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;SAC/D,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,YAAY,CACzB,GAAG,EACH,OAAO,EACP,MAAM,CAAC,QAAQ,EACf;YACE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACtD,EACD,OAAO,CAAC,GAAG,CACZ,CAAC;QACF,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QAEnC,OAAO,GAAG,CAAC,OAAO,CAChB;YACE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACrD,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,EACD,eAAe,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,YAAY,CAAC,MAAM,eAAe,OAAO,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,WAAW,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAC3O,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { harnessPinsResolver } from '../dev-experience';\nimport { runExperienceChecks } from '../experience/checks';\nimport { readExperienceProject } from '../experience/project';\nimport { failOnErrors } from '../experience/report';\nimport type { ExperienceCommand } from './index-experience';\n\nexport const checkCommand: ExperienceCommand = {\n name: 'check',\n usage: [\n ' check Run the experience gate: integration pins, generated types, integration-',\n ' import boundary (source + bundle), fixtures, definition, typecheck',\n ],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n typecheck: {\n type: 'boolean',\n default: true,\n description: 'Run tsc over the project (--no-typecheck skips)',\n },\n },\n async run(ctx, args) {\n const project = readExperienceProject(args.dir);\n const result = await runExperienceChecks(project, {\n typecheck: args.flags.typecheck !== false,\n loadDefinition: true,\n inlineSdk: args.env.EKANOS_INLINE_SDK,\n pinsResolver: await harnessPinsResolver(project.dir, args.env),\n });\n\n const failed = failOnErrors(\n ctx,\n 'check',\n result.findings,\n {\n slug: project.slug,\n integrations: project.integrations.map((u) => u.name),\n },\n project.dir,\n );\n if (failed !== null) return failed;\n\n return ctx.succeed(\n {\n slug: project.slug,\n integrations: project.integrations.map((u) => u.name),\n findings: result.findings,\n },\n `check: OK - ${project.slug} (${project.integrations.length} integration${project.integrations.length === 1 ? '' : 's'})${result.findings.length ? `, ${result.findings.length} warning${result.findings.length === 1 ? '' : 's'}` : ''}.`,\n );\n },\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import type { ExperienceCommand } from './index-experience.js';
2
+ export declare const codegenCommand: ExperienceCommand;
@@ -0,0 +1,49 @@
1
+ import { preconditionError, validationError } from '../errors.js';
2
+ import { expectedIntegrationsDts } from '../experience/checks.js';
3
+ import { readExperienceProject } from '../experience/project.js';
4
+ import { loadPins, regenerateIntegrations } from '../experience/regenerate.js';
5
+ export const codegenCommand = {
6
+ name: 'codegen',
7
+ usage: [
8
+ ' codegen Regenerate src/.ekanos/integrations.d.ts from the pinned contracts',
9
+ ' (offline, idempotent; --check fails when it is stale)',
10
+ ],
11
+ specs: {
12
+ dir: {
13
+ type: 'string',
14
+ description: 'Project directory (default: the current one)',
15
+ },
16
+ check: {
17
+ type: 'boolean',
18
+ description: 'Fail when the committed file differs; write nothing',
19
+ },
20
+ },
21
+ async run(ctx, args) {
22
+ const project = readExperienceProject(args.dir);
23
+ const { pinned, missing } = loadPins(project);
24
+ if (missing.length > 0) {
25
+ throw preconditionError(`No pinned contract for integration${missing.length === 1 ? '' : 's'}: ${missing.join(', ')}.`, 'Run "ekanos add <integration>@<version> --from-dir <contracts folder>" or "ekanos sync" first.');
26
+ }
27
+ if (args.flags.check === true) {
28
+ const fs = await import('node:fs');
29
+ const path = await import('node:path');
30
+ const file = path.join(project.dir, 'src/.ekanos/integrations.d.ts');
31
+ const current = fs.existsSync(file)
32
+ ? fs.readFileSync(file, 'utf8')
33
+ : null;
34
+ if (current !== expectedIntegrationsDts(pinned)) {
35
+ throw validationError('src/.ekanos/integrations.d.ts is stale.', 'Run "ekanos codegen" and commit the result.');
36
+ }
37
+ return ctx.succeed({ changed: false, integrations: pinned.length }, 'integrations.d.ts is up to date.');
38
+ }
39
+ const changed = regenerateIntegrations(project, pinned);
40
+ return ctx.succeed({
41
+ changed,
42
+ integrations: pinned.length,
43
+ file: 'src/.ekanos/integrations.d.ts',
44
+ }, changed
45
+ ? `Wrote src/.ekanos/integrations.d.ts (${pinned.length} integration${pinned.length === 1 ? '' : 's'}).`
46
+ : 'integrations.d.ts is already up to date.');
47
+ },
48
+ };
49
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/commands/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG5E,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE;QACL,iFAAiF;QACjF,oEAAoE;KACrE;IACD,KAAK,EAAE;QACL,GAAG,EAAE;YACH,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,8CAA8C;SAC5D;QACD,KAAK,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,qDAAqD;SACnE;KACF;IACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;QACjB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,iBAAiB,CACrB,qCAAqC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAC9F,gGAAgG,CACjG,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9B,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,+BAA+B,CAAC,CAAC;YACrE,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;gBACjC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC;YACT,IAAI,OAAO,KAAK,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChD,MAAM,eAAe,CACnB,yCAAyC,EACzC,6CAA6C,CAC9C,CAAC;YACJ,CAAC;YAED,OAAO,GAAG,CAAC,OAAO,CAChB,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,EAC/C,kCAAkC,CACnC,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAExD,OAAO,GAAG,CAAC,OAAO,CAChB;YACE,OAAO;YACP,YAAY,EAAE,MAAM,CAAC,MAAM;YAC3B,IAAI,EAAE,+BAA+B;SACtC,EACD,OAAO;YACL,CAAC,CAAC,wCAAwC,MAAM,CAAC,MAAM,eAAe,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;YACxG,CAAC,CAAC,0CAA0C,CAC/C,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { preconditionError, validationError } from '../errors';\nimport { expectedIntegrationsDts } from '../experience/checks';\nimport { readExperienceProject } from '../experience/project';\nimport { loadPins, regenerateIntegrations } from '../experience/regenerate';\nimport type { ExperienceCommand } from './index-experience';\n\nexport const codegenCommand: ExperienceCommand = {\n name: 'codegen',\n usage: [\n ' codegen Regenerate src/.ekanos/integrations.d.ts from the pinned contracts',\n ' (offline, idempotent; --check fails when it is stale)',\n ],\n specs: {\n dir: {\n type: 'string',\n description: 'Project directory (default: the current one)',\n },\n check: {\n type: 'boolean',\n description: 'Fail when the committed file differs; write nothing',\n },\n },\n async run(ctx, args) {\n const project = readExperienceProject(args.dir);\n const { pinned, missing } = loadPins(project);\n if (missing.length > 0) {\n throw preconditionError(\n `No pinned contract for integration${missing.length === 1 ? '' : 's'}: ${missing.join(', ')}.`,\n 'Run \"ekanos add <integration>@<version> --from-dir <contracts folder>\" or \"ekanos sync\" first.',\n );\n }\n\n if (args.flags.check === true) {\n const fs = await import('node:fs');\n const path = await import('node:path');\n const file = path.join(project.dir, 'src/.ekanos/integrations.d.ts');\n const current = fs.existsSync(file)\n ? fs.readFileSync(file, 'utf8')\n : null;\n if (current !== expectedIntegrationsDts(pinned)) {\n throw validationError(\n 'src/.ekanos/integrations.d.ts is stale.',\n 'Run \"ekanos codegen\" and commit the result.',\n );\n }\n\n return ctx.succeed(\n { changed: false, integrations: pinned.length },\n 'integrations.d.ts is up to date.',\n );\n }\n\n const changed = regenerateIntegrations(project, pinned);\n\n return ctx.succeed(\n {\n changed,\n integrations: pinned.length,\n file: 'src/.ekanos/integrations.d.ts',\n },\n changed\n ? `Wrote src/.ekanos/integrations.d.ts (${pinned.length} integration${pinned.length === 1 ? '' : 's'}).`\n : 'integrations.d.ts is already up to date.',\n );\n },\n};\n"]}
@@ -0,0 +1,52 @@
1
+ import { type Contract } from '@ekanos/integration-schema';
2
+ import type { CliContext } from '../context.js';
3
+ import { type HarnessResolver } from '../dev-experience.js';
4
+ import type { ExitCode } from '../exit-codes.js';
5
+ import type { ExperienceCommand } from './index-experience.js';
6
+ /** The slice of `@ekanos/sdk/contract` this command uses. */
7
+ export interface ContractModule {
8
+ analyzeContract(definition: unknown, options: {
9
+ packageVersion: string;
10
+ contractVersion: string;
11
+ previous?: Contract | null;
12
+ examples?: Readonly<Record<string, unknown>>;
13
+ }): {
14
+ contract: Contract;
15
+ diagnostics: Array<{
16
+ rule: string;
17
+ severity: 'error' | 'warn' | 'info';
18
+ message: string;
19
+ operation?: string;
20
+ }>;
21
+ };
22
+ synthesizeExample(schema: unknown): unknown;
23
+ }
24
+ export interface ContractArgs {
25
+ dir: string;
26
+ check: boolean;
27
+ record: boolean;
28
+ bump: boolean;
29
+ env?: Record<string, string | undefined>;
30
+ /**
31
+ * `--record --op tool/x[,action/y]`: record REAL examples for these
32
+ * operations from a run through the harness runner, instead of writing
33
+ * placeholders.
34
+ */
35
+ ops?: string[];
36
+ /** Which run mode produces the example (default `fixtures`). */
37
+ from?: 'fixtures' | 'live';
38
+ /** JSON input for the recorded run (single `--op` only); default: synthesized from the input schema. */
39
+ input?: string;
40
+ /** Test seam; the default loads the project's installed `@ekanos/harness/resolver`. */
41
+ loadHarness?: (projectDir: string) => Promise<HarnessResolver>;
42
+ /** Test seam; the default loads `@ekanos/sdk/contract` from the project. */
43
+ loadModule?: (projectDir: string) => Promise<ContractModule>;
44
+ }
45
+ /** The smallest contractVersion that satisfies the transition rules. */
46
+ export declare function nextContractVersion(previous: Contract, next: Contract): string | null;
47
+ /**
48
+ * `ekanos contract`: derive `contract.json` from the integration definition.
49
+ * See the command's usage text for the three modes.
50
+ */
51
+ export declare function runContract(ctx: CliContext, args: ContractArgs): Promise<ExitCode>;
52
+ export declare const contractCommand: ExperienceCommand;