@ekanos/cli 0.22.0 → 0.23.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 (77) hide show
  1. package/README.md +18 -4
  2. package/dist/commands/add.js +21 -10
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/contract.js +12 -2
  5. package/dist/commands/contract.js.map +1 -1
  6. package/dist/commands/dev.js +33 -2
  7. package/dist/commands/dev.js.map +1 -1
  8. package/dist/commands/publish.d.ts +6 -0
  9. package/dist/commands/publish.js +80 -4
  10. package/dist/commands/publish.js.map +1 -1
  11. package/dist/commands/status.d.ts +44 -0
  12. package/dist/commands/status.js +79 -18
  13. package/dist/commands/status.js.map +1 -1
  14. package/dist/commands/upgrade.js +287 -144
  15. package/dist/commands/upgrade.js.map +1 -1
  16. package/dist/docs-links.js +5 -1
  17. package/dist/docs-links.js.map +1 -1
  18. package/dist/errors.d.ts +2 -0
  19. package/dist/errors.js +9 -0
  20. package/dist/errors.js.map +1 -1
  21. package/dist/exit-codes.d.ts +3 -0
  22. package/dist/exit-codes.js +3 -0
  23. package/dist/exit-codes.js.map +1 -1
  24. package/dist/experience/checks.js +2 -1
  25. package/dist/experience/checks.js.map +1 -1
  26. package/dist/experience/definition-checks.d.ts +7 -0
  27. package/dist/experience/definition-checks.js +36 -4
  28. package/dist/experience/definition-checks.js.map +1 -1
  29. package/dist/experience/init.js +10 -0
  30. package/dist/experience/init.js.map +1 -1
  31. package/dist/experience/load-experience.js +33 -2
  32. package/dist/experience/load-experience.js.map +1 -1
  33. package/dist/experience/pins.d.ts +10 -0
  34. package/dist/experience/pins.js +19 -1
  35. package/dist/experience/pins.js.map +1 -1
  36. package/dist/generated/phosphor-names.d.ts +3 -0
  37. package/dist/generated/phosphor-names.js +1541 -0
  38. package/dist/generated/phosphor-names.js.map +1 -0
  39. package/dist/harness-scaffold.d.ts +13 -0
  40. package/dist/harness-scaffold.js +19 -3
  41. package/dist/harness-scaffold.js.map +1 -1
  42. package/dist/icon-findings.d.ts +12 -17
  43. package/dist/icon-findings.js +49 -74
  44. package/dist/icon-findings.js.map +1 -1
  45. package/dist/index.js +28 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/lockfile-instances.d.ts +60 -0
  48. package/dist/lockfile-instances.js +177 -0
  49. package/dist/lockfile-instances.js.map +1 -0
  50. package/dist/pack-hygiene.d.ts +8 -0
  51. package/dist/pack-hygiene.js +57 -0
  52. package/dist/pack-hygiene.js.map +1 -0
  53. package/dist/package-manager.d.ts +34 -6
  54. package/dist/package-manager.js +130 -20
  55. package/dist/package-manager.js.map +1 -1
  56. package/dist/project.js +11 -0
  57. package/dist/project.js.map +1 -1
  58. package/dist/repo/scaffold.js +4 -0
  59. package/dist/repo/scaffold.js.map +1 -1
  60. package/dist/schema-skew.js.map +1 -1
  61. package/dist/validate-findings.js +10 -1
  62. package/dist/validate-findings.js.map +1 -1
  63. package/dist/workspace-root.d.ts +16 -0
  64. package/dist/workspace-root.js +50 -0
  65. package/dist/workspace-root.js.map +1 -0
  66. package/package.json +4 -4
  67. package/templates/AGENTS.md.tmpl +11 -15
  68. package/templates/experience/package.json.tmpl +8 -6
  69. package/templates/experience/src/widgets/hello-widget.test.tsx.tmpl +49 -0
  70. package/templates/experience/vitest.config.ts.tmpl +21 -0
  71. package/templates/harness/next.config.mjs.tmpl +7 -4
  72. package/templates/package.json.tmpl +5 -5
  73. package/templates/skills/build-integration/references/widget-design.md +2 -3
  74. package/templates/skills/polish-widgets/references/patterns.md +5 -5
  75. package/dist/generated/fa-free-names.d.ts +0 -9
  76. package/dist/generated/fa-free-names.js +0 -2599
  77. package/dist/generated/fa-free-names.js.map +0 -1
@@ -0,0 +1,49 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
+ import { renderToStaticMarkup } from 'react-dom/server';
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ import { WidgetPreviewProvider } from '@ekanos/sdk/components';
8
+ import { ExperienceRuntimeProvider } from '@ekanos/sdk/experience/client';
9
+ import type { ExperienceRuntime } from '@ekanos/sdk/experience/runtime';
10
+
11
+ import { HelloWidget } from './hello-widget';
12
+
13
+ // Widget.* needs the host's widget context, which WidgetPreviewProvider
14
+ // stands in for (state="loading" | "error" walks the other branches).
15
+ //
16
+ // A stand-in for the host's runtime. A widget that calls
17
+ // useOperation('<integration>', 'tool/<name>') reaches it through
18
+ // `call`: return { ok: true, data } or { ok: false, reason, message } to
19
+ // test the happy path and a refusal.
20
+ const runtime: ExperienceRuntime = {
21
+ call: async () => ({
22
+ ok: false,
23
+ reason: 'binding_missing',
24
+ message: 'Not connected in a test.',
25
+ }),
26
+ integrations: () => [],
27
+ };
28
+
29
+ function render(node: ReactNode) {
30
+ const client = new QueryClient({
31
+ defaultOptions: { queries: { retry: false } },
32
+ });
33
+
34
+ return renderToStaticMarkup(
35
+ <QueryClientProvider client={client}>
36
+ <ExperienceRuntimeProvider runtime={runtime}>
37
+ <WidgetPreviewProvider widgetId="hello" title="Hello">
38
+ {node}
39
+ </WidgetPreviewProvider>
40
+ </ExperienceRuntimeProvider>
41
+ </QueryClientProvider>,
42
+ );
43
+ }
44
+
45
+ describe('HelloWidget', () => {
46
+ it('renders inside the experience runtime', () => {
47
+ expect(render(<HelloWidget />)).toContain('Integrations');
48
+ });
49
+ });
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ // Widgets are rendered to a string with react-dom/server, so no DOM
7
+ // environment is needed. Add jsdom and a testing library only if you
8
+ // start testing interaction.
9
+ environment: 'node',
10
+ include: ['src/**/*.test.{ts,tsx}'],
11
+ // REQUIRED — do not remove. The published @ekanos/sdk dist imports the
12
+ // extensionless "next/link"; without inlining the SDK here, vitest cannot
13
+ // transform and load it, your test files import nothing, and vitest reports
14
+ // GREEN over zero tests.
15
+ server: {
16
+ deps: {
17
+ inline: ['@ekanos/sdk', '@ekanos/ui'],
18
+ },
19
+ },
20
+ },
21
+ });
@@ -6,10 +6,13 @@ import { fileURLToPath } from 'node:url';
6
6
  /**
7
7
  * The shell lives two directories below your project root and has no
8
8
  * node_modules of its own; `next`, `react` and `@ekanos/harness` all resolve
9
- * upward into yours. Pointing Next at that root stops it inferring a different
10
- * one and keeps file watching over your integration source.
9
+ * upward into yours. Inside a workspace (pnpm, npm or yarn workspaces, or an
10
+ * Ekanos repo) they live in the WORKSPACE root's node_modules instead, so this
11
+ * is that root. Pointing Next at it stops it inferring a different one, lets
12
+ * it follow the package manager's links, and keeps file watching over your
13
+ * source, which sits inside it.
11
14
  */
12
- const projectRoot = fileURLToPath(new URL('../../', import.meta.url));
15
+ const turbopackRoot = fileURLToPath(new URL(__TURBOPACK_ROOT__, import.meta.url));
13
16
 
14
17
  /** @type {import('next').NextConfig} */
15
18
  const config = {
@@ -21,7 +24,7 @@ const config = {
21
24
  // and the harness renders in the system font stack, with no error.
22
25
  transpilePackages: ['@ekanos/harness'],
23
26
  turbopack: {
24
- root: projectRoot,
27
+ root: turbopackRoot,
25
28
  resolveAlias: {
26
29
  // A widget written for the real Ekanos host imports
27
30
  // `useTeamAccountWorkspace()` to read `account.slug`. That module
@@ -12,12 +12,12 @@
12
12
  "prepare": "node scripts/setup-hooks.mjs"
13
13
  },
14
14
  "dependencies": {
15
- "@ekanos/sdk": "^0.24.0",
16
- "@ekanos/ui": "^0.24.0"
15
+ "@ekanos/sdk": "^0.26.0",
16
+ "@ekanos/ui": "^0.26.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@ekanos/cli": "^0.22.0",
20
- "@ekanos/harness": "^0.24.0",
19
+ "@ekanos/cli": "^0.23.0",
20
+ "@ekanos/harness": "^0.26.0",
21
21
  "@hookform/resolvers": "^5.2.2",
22
22
  "@tailwindcss/postcss": "^4.3.3",
23
23
  "@tanstack/react-query": "^5.101.4",
@@ -34,6 +34,6 @@
34
34
  "tailwindcss": "^4.3.3",
35
35
  "typescript": "^5.9.3",
36
36
  "vitest": "4.1.10",
37
- "zod": "^3.25.76"
37
+ "zod": "^4.6.7"
38
38
  }
39
39
  }
@@ -215,9 +215,8 @@ mock switch) so the harness can show all four; remove it before publish.
215
215
  state, `card`/`dialog`/`select`/`input` for the rest. Never hand-roll a
216
216
  button, input, select, label or status pill out of raw HTML elements;
217
217
  `ekanos validate` warns on each one. `cn()` from `@ekanos/ui/utils` for
218
- conditional classes; icons through `@ekanos/ui/icon` (Font Awesome names —
219
- they render empty outside a host that loads FA; that is expected in bare
220
- tests).
218
+ conditional classes; icons through `@ekanos/ui/icon` (Phosphor names from
219
+ phosphoricons.com, such as `house`).
221
220
  - **No inline styles**: `style={{ … }}` escapes the theme entirely — no dark
222
221
  mode, no Source branding, no lint. Everything is a Tailwind class.
223
222
 
@@ -1,8 +1,8 @@
1
1
  # Widget fix patterns — before → after
2
2
 
3
3
  Each pattern names the failure, then shows the smallest honest fix. All
4
- imports are `@ekanos/ui/*`; icons go through `@ekanos/ui/icon` (Font Awesome
5
- names — verify against the Free set). Everything sits inside the standard
4
+ imports are `@ekanos/ui/*`; icons go through `@ekanos/ui/icon` (Phosphor
5
+ names from phosphoricons.com). Everything sits inside the standard
6
6
  `Widget.Active` body from the SDK's compound API; these are the bodies, not
7
7
  the wrapper.
8
8
 
@@ -184,7 +184,7 @@ is not information-rich; it is unreadable.
184
184
  <div className="space-y-1 p-2">
185
185
  {events.map((e) => (
186
186
  <div key={e.id} className="flex gap-1 text-xs">
187
- <Icon name="fa-bolt" className="h-3 w-3" />
187
+ <Icon name="lightning" className="h-3 w-3" />
188
188
  <span>{e.title}</span>
189
189
  </div>
190
190
  ))}
@@ -268,7 +268,7 @@ import {
268
268
  <DropdownMenuTrigger
269
269
  render={<Button variant="ghost" size="icon" className="h-8 w-8" />}
270
270
  >
271
- <Icon name="fa-ellipsis-vertical" className="h-4 w-4" />
271
+ <Icon name="dots-three-vertical" className="h-4 w-4" />
272
272
  </DropdownMenuTrigger>
273
273
  <DropdownMenuContent align="end">
274
274
  <DropdownMenuItem>View details</DropdownMenuItem>
@@ -293,7 +293,7 @@ said, and it matches every other widget on the board:
293
293
  ```tsx
294
294
  // AFTER — the SDK's empty state, one sentence of what appears here
295
295
  <Widget.Empty
296
- icon="fa-inbox"
296
+ icon="tray"
297
297
  title="No invoices yet"
298
298
  description="Invoices appear here as soon as your first one is issued."
299
299
  />
@@ -1,9 +0,0 @@
1
- export declare const FA_FREE_VERSION = "7.3.1";
2
- /** Every icon name Font Awesome Free ships — NOT Ekanos's set (Pro, a superset). */
3
- export declare const FA_FREE_ICON_NAMES: ReadonlySet<string>;
4
- /**
5
- * Hand-curated Pro-only name → nearest Free alternative, sourced from
6
- * @ekanos/harness's Pro→Free glyph shim. Not exhaustive — a Pro-only name
7
- * with no shim entry has no known Free substitute here.
8
- */
9
- export declare const FA_PRO_TO_FREE_HINTS: ReadonlyMap<string, string>;