aeon-ui-engine 1.3.1 → 1.4.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/CHANGELOG.md +61 -0
- package/package.json +1 -1
- package/packages/cli/README.md +13 -1
- package/packages/cli/dist/bin.js +23 -5
- package/packages/cli/dist/chunk-5L47SLNV.js +247 -0
- package/packages/cli/dist/index.d.ts +17 -1
- package/packages/cli/dist/index.js +5 -3
- package/packages/cli/src/bin.ts +21 -3
- package/packages/cli/src/index.ts +1 -0
- package/packages/cli/src/migrate.ts +170 -0
- package/packages/core/dist/index.d.ts +35 -7
- package/packages/core/dist/index.js +102 -2
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/core/src/anatomy.ts +39 -3
- package/packages/core/src/identicon.test.ts +39 -0
- package/packages/core/src/identicon.ts +79 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/panda/panda.config.ts +4 -0
- package/packages/panda/src/recipes/composer.ts +58 -4
- package/packages/panda/src/recipes/file-upload.ts +100 -0
- package/packages/panda/src/recipes/index.ts +2 -0
- package/packages/panda/src/recipes/range-slider.ts +59 -0
- package/packages/panda/src/recipes/thread.ts +77 -2
- package/packages/panda/styled-system/recipes/aeon-composer.d.ts +1 -1
- package/packages/panda/styled-system/recipes/aeon-composer.mjs +12 -0
- package/packages/panda/styled-system/recipes/aeon-file-upload.d.ts +31 -0
- package/packages/panda/styled-system/recipes/aeon-file-upload.mjs +61 -0
- package/packages/panda/styled-system/recipes/aeon-range-slider.d.ts +31 -0
- package/packages/panda/styled-system/recipes/aeon-range-slider.mjs +49 -0
- package/packages/panda/styled-system/recipes/aeon-thread.d.ts +1 -1
- package/packages/panda/styled-system/recipes/aeon-thread.mjs +20 -0
- package/packages/panda/styled-system/recipes/index.d.ts +2 -0
- package/packages/panda/styled-system/recipes/index.mjs +2 -0
- package/packages/panda/styled-system/styles.css +292 -0
- package/packages/primitives/dist/chunk-CV4UXXZF.js +44 -0
- package/packages/primitives/dist/chunk-IZKQSCYU.js +164 -0
- package/packages/primitives/dist/index.d.ts +2 -0
- package/packages/primitives/dist/index.js +22 -6
- package/packages/primitives/dist/machines/file-upload.d.ts +39 -0
- package/packages/primitives/dist/machines/file-upload.js +8 -0
- package/packages/primitives/dist/machines/range-slider.d.ts +129 -0
- package/packages/primitives/dist/machines/range-slider.js +12 -0
- package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/primitives/src/__tests__/file-upload.test.ts +25 -0
- package/packages/primitives/src/__tests__/range-slider.test.ts +39 -0
- package/packages/primitives/src/index.ts +2 -0
- package/packages/primitives/src/machines/file-upload.ts +55 -0
- package/packages/primitives/src/machines/range-slider.ts +209 -0
- package/packages/react/dist/index.d.ts +117 -25
- package/packages/react/dist/index.js +1731 -1006
- package/packages/react/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/react/src/button/index.tsx +50 -15
- package/packages/react/src/combobox/index.tsx +13 -8
- package/packages/react/src/composer/index.tsx +58 -3
- package/packages/react/src/file-upload/index.tsx +322 -0
- package/packages/react/src/index.ts +3 -0
- package/packages/react/src/prompt/index.tsx +45 -0
- package/packages/react/src/range-slider/index.tsx +322 -0
- package/packages/react/src/thread/index.tsx +74 -3
- package/packages/react/src/tooltip/index.tsx +48 -22
- package/packages/react/src/utils/slot.tsx +47 -0
- package/packages/schemas/dist/index.d.ts +73 -24
- package/packages/schemas/dist/index.js +514 -50
- package/packages/schemas/json/appNav.json +146 -0
- package/packages/schemas/json/appShell.json +151 -0
- package/packages/schemas/json/avatar.json +130 -0
- package/packages/schemas/json/bar.json +126 -0
- package/packages/schemas/json/button.json +6 -0
- package/packages/schemas/json/catalog.json +3496 -15
- package/packages/schemas/json/combobox.json +19 -7
- package/packages/schemas/json/composer.json +125 -0
- package/packages/schemas/json/content.json +167 -0
- package/packages/schemas/json/conversation.json +166 -0
- package/packages/schemas/json/entry.json +182 -0
- package/packages/schemas/json/fileUpload.json +168 -0
- package/packages/schemas/json/identity.json +147 -0
- package/packages/schemas/json/listRow.json +131 -0
- package/packages/schemas/json/metricStrip.json +132 -0
- package/packages/schemas/json/nav.json +136 -0
- package/packages/schemas/json/panel.json +143 -0
- package/packages/schemas/json/pinInput.json +112 -0
- package/packages/schemas/json/profileHeader.json +138 -0
- package/packages/schemas/json/prompt.json +155 -0
- package/packages/schemas/json/radioGroup.json +130 -0
- package/packages/schemas/json/rangeSlider.json +157 -0
- package/packages/schemas/json/separator.json +105 -0
- package/packages/schemas/json/slider.json +147 -0
- package/packages/schemas/json/statusBanner.json +149 -0
- package/packages/schemas/json/stickyBar.json +153 -0
- package/packages/schemas/json/thread.json +129 -0
- package/packages/schemas/json/tooltip.json +21 -7
- package/packages/schemas/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/schemas/prompts/cursorrules.md +6 -4
- package/packages/schemas/prompts/statecharts.md +23 -2
- package/packages/schemas/prompts/system.md +2 -2
- package/packages/schemas/registry/catalog.json +313 -4
- package/packages/schemas/registry/components/appNav.json +146 -0
- package/packages/schemas/registry/components/appShell.json +151 -0
- package/packages/schemas/registry/components/avatar.json +130 -0
- package/packages/schemas/registry/components/bar.json +126 -0
- package/packages/schemas/registry/components/button.json +6 -0
- package/packages/schemas/registry/components/combobox.json +19 -7
- package/packages/schemas/registry/components/composer.json +125 -0
- package/packages/schemas/registry/components/content.json +167 -0
- package/packages/schemas/registry/components/conversation.json +166 -0
- package/packages/schemas/registry/components/entry.json +182 -0
- package/packages/schemas/registry/components/fileUpload.json +168 -0
- package/packages/schemas/registry/components/identity.json +147 -0
- package/packages/schemas/registry/components/listRow.json +131 -0
- package/packages/schemas/registry/components/metricStrip.json +132 -0
- package/packages/schemas/registry/components/nav.json +136 -0
- package/packages/schemas/registry/components/panel.json +143 -0
- package/packages/schemas/registry/components/pinInput.json +112 -0
- package/packages/schemas/registry/components/profileHeader.json +138 -0
- package/packages/schemas/registry/components/prompt.json +155 -0
- package/packages/schemas/registry/components/radioGroup.json +130 -0
- package/packages/schemas/registry/components/rangeSlider.json +157 -0
- package/packages/schemas/registry/components/separator.json +105 -0
- package/packages/schemas/registry/components/slider.json +147 -0
- package/packages/schemas/registry/components/statusBanner.json +149 -0
- package/packages/schemas/registry/components/stickyBar.json +153 -0
- package/packages/schemas/registry/components/thread.json +129 -0
- package/packages/schemas/registry/components/tooltip.json +21 -7
- package/packages/schemas/registry/machines/accordion.json +58 -0
- package/packages/schemas/registry/machines/appNav.json +108 -0
- package/packages/schemas/registry/machines/appShell.json +128 -0
- package/packages/schemas/registry/machines/contentRegion.json +314 -0
- package/packages/schemas/registry/machines/fileUpload.json +182 -0
- package/packages/schemas/registry/machines/panel.json +131 -0
- package/packages/schemas/registry/machines/popover.json +143 -0
- package/packages/schemas/registry/machines/rangeSlider.json +201 -0
- package/packages/schemas/registry/machines/slider.json +151 -0
- package/packages/schemas/registry/machines/stickyBar.json +261 -0
- package/packages/schemas/registry/machines/tabs.json +58 -0
- package/packages/schemas/registry/machines/toast.json +89 -0
- package/packages/schemas/registry/machines/toggle.json +134 -0
- package/packages/schemas/scripts/emit.ts +27 -0
- package/packages/schemas/src/components.ts +499 -6
- package/packages/schemas/src/index.test.ts +83 -0
- package/packages/schemas/src/index.ts +1 -0
- package/packages/schemas/src/machine-id.ts +7 -0
- package/packages/schemas/src/prompts.ts +25 -4
- package/packages/schemas/src/registry.ts +28 -39
- package/packages/schemas/tsconfig.json +1 -1
- package/packages/ui/dist/index.d.ts +100 -46
- package/packages/ui/dist/index.js +463 -341
- package/packages/ui/src/composer.tsx +37 -11
- package/packages/ui/src/file-upload.tsx +36 -0
- package/packages/ui/src/index.ts +2 -0
- package/packages/ui/src/prompt.tsx +3 -0
- package/packages/ui/src/range-slider.tsx +24 -0
- package/packages/ui/src/thread.tsx +40 -0
- package/packages/cli/dist/chunk-IW5NT2Z2.js +0 -103
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.0] - 2026-08-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **RangeSlider** — `rangeSliderMachine` + headless/styled compound (two thumbs, `minStepsBetween`).
|
|
8
|
+
- **FileUpload** — `fileUploadMachine` + dropzone compound (`idle | dragging | rejected`; file bytes in React).
|
|
9
|
+
- **Button `asChild`** + exported `Slot` — merge button attrs onto `Link` / `<a>`.
|
|
10
|
+
- **`npx aeon-ui migrate`** — scan known workarounds + write `AEON_MIGRATION_CHECKLIST.md`.
|
|
11
|
+
- **docs/MIGRATION.md** — greenfield + upgrade playbook for future app migrations.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- COMPONENTS / MACHINES / PRIMITIVE_COVERAGE / API_PATTERNS updated for 1.4 primitives.
|
|
16
|
+
|
|
17
|
+
## [1.3.6] - 2026-07-31
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Landing hero** — “A better way to build with AI” (title, OG, tagline).
|
|
22
|
+
- **Builder statecharts** — live chart follows the active UX scope/machine and highlights more reliably as you interact.
|
|
23
|
+
|
|
24
|
+
### Earlier in 1.3.6
|
|
25
|
+
|
|
26
|
+
- **Landing why-first** — philosophy, pillars, FAQ, and charts/totality support that outcome instead of leading with mechanics.
|
|
27
|
+
|
|
28
|
+
## [1.3.5] - 2026-07-31
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Layout schemas for Instant/agent surfaces: identity, profileHeader, metricStrip, listRow, entry, conversation (38 total schemas).
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- **Tooltip open/closed** — uses `popoverMachine` like Popover/Select/Combobox; openDelay / closeDelay / touchDuration stay React-local.
|
|
37
|
+
- Agent prompts and MACHINES/COMPONENTS/FILE_MAP now treat Tooltip as popover-family.
|
|
38
|
+
|
|
39
|
+
## [1.3.4] - 2026-07-31
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- Instant/Build no longer shows chart-only stubs like “States: idle · discover · … Project faces in a second pass.” — projects concept/prompt faces while keeping the authored chart.
|
|
44
|
+
|
|
45
|
+
## [1.3.3] - 2026-07-31
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **Agent registry lag** — runtime `registry/catalog.json` now derives from `componentSchemas` (was stuck at 4 entries while schemas existed).
|
|
50
|
+
- **Machine emit coverage** — schema emit writes all 15 primitives machines (was only async/button/dialog/field), unlocking `validEvents` trees for popover family, slider, shells, etc.
|
|
51
|
+
- **Combobox open/closed** — uses `popoverMachine` like Select; query/highlight stay React-local.
|
|
52
|
+
- Stale docs claiming Select/Combobox were pure `useState`; checklist now requires schema + emit steps.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- Component schemas for machine-backed and high-traffic surfaces: radioGroup, slider, content, panel, appShell, stickyBar, nav, appNav, prompt, statusBanner, pinInput, avatar, bar, separator, composer, thread (32 total).
|
|
57
|
+
|
|
58
|
+
## [1.3.2] - 2026-07-31
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- Restore state-first landing messaging (remove BETA chrome from hero, meta, and builder).
|
|
63
|
+
|
|
3
64
|
## [1.3.1] - 2026-07-30
|
|
4
65
|
|
|
5
66
|
### Changed
|
package/package.json
CHANGED
package/packages/cli/README.md
CHANGED
|
@@ -4,14 +4,26 @@ AI-optimized CLI for Aeon UI.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx aeon-ui init
|
|
7
|
+
npx aeon-ui migrate
|
|
7
8
|
```
|
|
8
9
|
|
|
10
|
+
## `init`
|
|
11
|
+
|
|
9
12
|
Injects:
|
|
10
13
|
|
|
11
14
|
- `.cursor/rules/aeon-ui.mdc` — always-on Cursor rule
|
|
12
15
|
- `aeon.cursorrules.md` / `aeon.system-prompt.md` — paste into any agent
|
|
13
16
|
- `aeon.schemas/` — deterministic JSON schemas per component
|
|
14
|
-
- `src/components/AeonStarter.tsx` — minimal Field + Button
|
|
17
|
+
- `src/components/AeonStarter.tsx` — minimal Field + Button scaffold
|
|
15
18
|
- `AEON_AI.md` — next steps
|
|
16
19
|
|
|
17
20
|
Use `--force` to overwrite.
|
|
21
|
+
|
|
22
|
+
## `migrate`
|
|
23
|
+
|
|
24
|
+
Scans for known local workarounds (preview-window machine, file dropzone, sonner bridge, etc.) and writes `AEON_MIGRATION_CHECKLIST.md`.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx aeon-ui migrate # write checklist
|
|
28
|
+
npx aeon-ui migrate --check # print findings only
|
|
29
|
+
```
|
package/packages/cli/dist/bin.js
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
initAeon
|
|
4
|
-
|
|
3
|
+
initAeon,
|
|
4
|
+
migrateAeon
|
|
5
|
+
} from "./chunk-5L47SLNV.js";
|
|
5
6
|
|
|
6
7
|
// src/bin.ts
|
|
7
8
|
var args = process.argv.slice(2);
|
|
8
9
|
var cmd = args[0] ?? "help";
|
|
9
10
|
var force = args.includes("--force") || args.includes("-f");
|
|
11
|
+
var checkOnly = args.includes("--check");
|
|
10
12
|
function help() {
|
|
11
13
|
console.log(`aeon-ui \u2014 AI-optimized CLI for Aeon UI
|
|
12
14
|
|
|
13
15
|
Usage:
|
|
14
16
|
npx aeon-ui init [--force]
|
|
17
|
+
npx aeon-ui migrate [--check]
|
|
15
18
|
|
|
16
19
|
Commands:
|
|
17
|
-
init
|
|
18
|
-
|
|
20
|
+
init Inject Cursor rules, JSON schemas, system prompt, and a starter component
|
|
21
|
+
migrate Scan for known workarounds and write AEON_MIGRATION_CHECKLIST.md
|
|
22
|
+
help Show this message
|
|
19
23
|
|
|
20
24
|
Options:
|
|
21
|
-
--force, -f Overwrite existing generated files
|
|
25
|
+
--force, -f Overwrite existing generated files (init)
|
|
26
|
+
--check Report findings only; do not write checklist (migrate)
|
|
22
27
|
`);
|
|
23
28
|
}
|
|
24
29
|
if (cmd === "init") {
|
|
@@ -27,6 +32,19 @@ if (cmd === "init") {
|
|
|
27
32
|
for (const line of result.written) console.log(` ${line}`);
|
|
28
33
|
console.log("\nNext: npm install aeon-ui-engine react react-dom xstate @xstate/react");
|
|
29
34
|
console.log("Docs: AEON_AI.md \xB7 paste aeon.cursorrules.md into your agent system prompt");
|
|
35
|
+
} else if (cmd === "migrate") {
|
|
36
|
+
const result = migrateAeon({ write: !checkOnly });
|
|
37
|
+
console.log(`Aeon UI migrate \u2192 ${result.cwd}`);
|
|
38
|
+
for (const line of result.written) console.log(` ${line}`);
|
|
39
|
+
if (result.findings.length === 0) {
|
|
40
|
+
console.log(" (no known workarounds matched in quick scan)");
|
|
41
|
+
} else {
|
|
42
|
+
for (const f of result.findings) {
|
|
43
|
+
console.log(` [${f.severity}] ${f.id}: ${f.advice}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
console.log("\nInstall: npm install aeon-ui-engine@^1.4.0 xstate @xstate/react");
|
|
47
|
+
console.log("Docs: https://aeon-ui.com \xB7 repo docs/MIGRATION.md");
|
|
30
48
|
} else {
|
|
31
49
|
help();
|
|
32
50
|
if (cmd !== "help" && cmd !== "--help" && cmd !== "-h") {
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// src/init.ts
|
|
2
|
+
import { mkdirSync, writeFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import {
|
|
5
|
+
CURSOR_RULES_SNIPPET,
|
|
6
|
+
AEON_SYSTEM_PROMPT,
|
|
7
|
+
catalog,
|
|
8
|
+
componentSchemas
|
|
9
|
+
} from "@aeon-ui/schemas";
|
|
10
|
+
var STARTER = `/**
|
|
11
|
+
* Aeon UI starter \u2014 generated by \`npx aeon-ui init\`
|
|
12
|
+
* Headless: @aeon-ui/react \xB7 Styled: @aeon-ui/ui \xB7 Schemas: @aeon-ui/schemas
|
|
13
|
+
*/
|
|
14
|
+
import { Button, Field } from '@aeon-ui/ui'
|
|
15
|
+
|
|
16
|
+
export function AeonStarter() {
|
|
17
|
+
return (
|
|
18
|
+
<div>
|
|
19
|
+
<Field.Root>
|
|
20
|
+
<Field.Label>Email</Field.Label>
|
|
21
|
+
<Field.Control type="email" placeholder="you@example.com" />
|
|
22
|
+
<Field.Message />
|
|
23
|
+
</Field.Root>
|
|
24
|
+
<Button.Root status="idle">Continue</Button.Root>
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
function initAeon(options = {}) {
|
|
30
|
+
const cwd = options.cwd ?? process.cwd();
|
|
31
|
+
const force = options.force ?? false;
|
|
32
|
+
const written = [];
|
|
33
|
+
const write = (rel, body) => {
|
|
34
|
+
const path = join(cwd, rel);
|
|
35
|
+
if (existsSync(path) && !force) {
|
|
36
|
+
written.push(`skip ${rel} (exists)`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
40
|
+
writeFileSync(path, body.endsWith("\n") ? body : `${body}
|
|
41
|
+
`);
|
|
42
|
+
written.push(`write ${rel}`);
|
|
43
|
+
};
|
|
44
|
+
write(".cursor/rules/aeon-ui.mdc", `---
|
|
45
|
+
description: Aeon UI \u2014 statechart-driven components for AI agents
|
|
46
|
+
globs: **/*.{tsx,ts,jsx,js}
|
|
47
|
+
alwaysApply: true
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
${CURSOR_RULES_SNIPPET.trim()}
|
|
51
|
+
`);
|
|
52
|
+
write("aeon.cursorrules.md", `${CURSOR_RULES_SNIPPET.trim()}
|
|
53
|
+
`);
|
|
54
|
+
write("aeon.system-prompt.md", `${AEON_SYSTEM_PROMPT.trim()}
|
|
55
|
+
`);
|
|
56
|
+
write(
|
|
57
|
+
"aeon.schemas/catalog.json",
|
|
58
|
+
`${JSON.stringify(
|
|
59
|
+
{
|
|
60
|
+
$id: catalog.$id,
|
|
61
|
+
title: catalog.title,
|
|
62
|
+
description: catalog.description,
|
|
63
|
+
version: catalog.version,
|
|
64
|
+
principle: catalog.principle,
|
|
65
|
+
attributes: catalog.attributes,
|
|
66
|
+
components: catalog.components,
|
|
67
|
+
note: "Full schemas live under aeon.schemas/components/*.json"
|
|
68
|
+
},
|
|
69
|
+
null,
|
|
70
|
+
2
|
|
71
|
+
)}
|
|
72
|
+
`
|
|
73
|
+
);
|
|
74
|
+
for (const [id, schema] of Object.entries(componentSchemas)) {
|
|
75
|
+
write(`aeon.schemas/components/${id}.json`, `${JSON.stringify(schema, null, 2)}
|
|
76
|
+
`);
|
|
77
|
+
}
|
|
78
|
+
write("src/components/AeonStarter.tsx", STARTER);
|
|
79
|
+
write(
|
|
80
|
+
"AEON_AI.md",
|
|
81
|
+
`# Aeon UI \u2014 AI agent setup
|
|
82
|
+
|
|
83
|
+
Generated by \`npx aeon-ui init\`.
|
|
84
|
+
|
|
85
|
+
## Next steps
|
|
86
|
+
|
|
87
|
+
1. Install: \`npm install aeon-ui-engine react react-dom xstate @xstate/react\`
|
|
88
|
+
2. CSS: \`import 'aeon-ui-engine/aeon.css'\`
|
|
89
|
+
3. Vite: add \`aeonUiVitePlugin()\` from \`aeon-ui-engine/vite\`
|
|
90
|
+
4. Paste \`aeon.cursorrules.md\` into Cursor rules / system prompt (already mirrored to \`.cursor/rules/aeon-ui.mdc\`)
|
|
91
|
+
5. Constrain generation with JSON under \`aeon.schemas/\`
|
|
92
|
+
|
|
93
|
+
## Principle
|
|
94
|
+
|
|
95
|
+
**UI = f(state)** \u2014 never invent boolean combinations for states the schema does not list.
|
|
96
|
+
`
|
|
97
|
+
);
|
|
98
|
+
return { cwd, written };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/migrate.ts
|
|
102
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
103
|
+
import { join as join2 } from "path";
|
|
104
|
+
var FINDINGS = [
|
|
105
|
+
{
|
|
106
|
+
id: "preview-window-machine",
|
|
107
|
+
severity: "replace",
|
|
108
|
+
patterns: ["preview-window-machine", "previewWindowMachine"],
|
|
109
|
+
advice: "Replace with RangeSlider from @aeon-ui/react or @aeon-ui/ui (rangeSliderMachine)."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "file-dropzone",
|
|
113
|
+
severity: "replace",
|
|
114
|
+
patterns: ["file-dropzone-machine", "fileDropzoneMachine", "FileDropzone"],
|
|
115
|
+
advice: "Replace with FileUpload compound (fileUploadMachine) \u2014 idle | dragging | rejected."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "sonner-bridge",
|
|
119
|
+
severity: "replace",
|
|
120
|
+
patterns: ["from 'sonner'", 'from "sonner"', "components/ui/sonner"],
|
|
121
|
+
advice: "Use Toast.Provider + useToast().publish / dismiss (aeon-ui-engine \u2265 1.2)."
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "manual-link-button",
|
|
125
|
+
severity: "optional",
|
|
126
|
+
patterns: ['data-aeon-scope="button"', "buttonVariants("],
|
|
127
|
+
advice: "Prefer <Button.Root asChild><Link \u2026 /></Button.Root> instead of hand-rolled data-aeon-* on anchors."
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "chakra",
|
|
131
|
+
severity: "info",
|
|
132
|
+
patterns: ["@chakra-ui/react", "@ark-ui/react"],
|
|
133
|
+
advice: "Migrate leaf \u2192 forms \u2192 overlays per docs/MIGRATION_FROM_ARK.md; see docs/MIGRATION.md for greenfield checklist."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "alert-dialog-local",
|
|
137
|
+
severity: "optional",
|
|
138
|
+
patterns: ["alertDialogMachine", 'role="alertdialog"'],
|
|
139
|
+
advice: "Prefer Dialog/Prompt with dismissible=false for destructive confirms until AlertDialog ships."
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
var CANDIDATES = [
|
|
143
|
+
"package.json",
|
|
144
|
+
"package-lock.json",
|
|
145
|
+
"pnpm-lock.yaml",
|
|
146
|
+
"lib/preview-window-machine.ts",
|
|
147
|
+
"lib/file-dropzone-machine.ts",
|
|
148
|
+
"components/file-dropzone.tsx",
|
|
149
|
+
"components/ui/sonner.tsx",
|
|
150
|
+
"components/ui/alert-dialog.tsx",
|
|
151
|
+
"components/ui/slider.tsx",
|
|
152
|
+
"components/ui/button.tsx",
|
|
153
|
+
"components/dual-login-buttons.tsx"
|
|
154
|
+
];
|
|
155
|
+
function walkHints(cwd) {
|
|
156
|
+
const hits = [];
|
|
157
|
+
let corpus = "";
|
|
158
|
+
for (const rel of CANDIDATES) {
|
|
159
|
+
const abs = join2(cwd, rel);
|
|
160
|
+
if (!existsSync2(abs)) continue;
|
|
161
|
+
try {
|
|
162
|
+
corpus += `
|
|
163
|
+
${rel}
|
|
164
|
+
${readFileSync(abs, "utf8")}`;
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const rule of FINDINGS) {
|
|
169
|
+
const matched = rule.patterns.find((p) => corpus.includes(p));
|
|
170
|
+
if (matched) {
|
|
171
|
+
hits.push({
|
|
172
|
+
id: rule.id,
|
|
173
|
+
severity: rule.severity,
|
|
174
|
+
pattern: matched,
|
|
175
|
+
advice: rule.advice
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return hits;
|
|
180
|
+
}
|
|
181
|
+
var CHECKLIST = `# Aeon migration checklist
|
|
182
|
+
|
|
183
|
+
Generated by \`npx aeon-ui migrate\`.
|
|
184
|
+
|
|
185
|
+
## Install
|
|
186
|
+
|
|
187
|
+
\`\`\`bash
|
|
188
|
+
npm install aeon-ui-engine@^1.4.0 react react-dom xstate @xstate/react
|
|
189
|
+
\`\`\`
|
|
190
|
+
|
|
191
|
+
\`\`\`ts
|
|
192
|
+
import 'aeon-ui-engine/aeon.css'
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
## Agent setup
|
|
196
|
+
|
|
197
|
+
\`\`\`bash
|
|
198
|
+
npx aeon-ui init
|
|
199
|
+
\`\`\`
|
|
200
|
+
|
|
201
|
+
Paste \`aeon.cursorrules.md\` into Cursor rules. Keep domain machines in the app; use Aeon for chrome + interactive primitives.
|
|
202
|
+
|
|
203
|
+
## Statechart-first rule
|
|
204
|
+
|
|
205
|
+
1. Model interaction with an XState machine (or reuse Aeon machines).
|
|
206
|
+
2. Project \`snapshot\` \u2192 \`data-aeon-state\` / compound parts.
|
|
207
|
+
3. Do not invent parallel booleans for chart-owned concerns.
|
|
208
|
+
|
|
209
|
+
## New primitives (1.4+)
|
|
210
|
+
|
|
211
|
+
| Need | Use |
|
|
212
|
+
|------|-----|
|
|
213
|
+
| Two-thumb range | \`RangeSlider\` + \`rangeSliderMachine\` |
|
|
214
|
+
| Link styled as button | \`<Button.Root asChild><Link/></Button.Root>\` |
|
|
215
|
+
| Drag-drop file surface | \`FileUpload\` + \`fileUploadMachine\` |
|
|
216
|
+
| Toast | \`Toast.Provider\` + \`useToast()\` |
|
|
217
|
+
| Confirm sheet | \`Prompt\` / \`Dialog\` |
|
|
218
|
+
|
|
219
|
+
## Docs
|
|
220
|
+
|
|
221
|
+
- docs/MIGRATION.md (in aeon-ui-engine / AeonUI repo)
|
|
222
|
+
- docs/MIGRATION_FROM_ARK.md
|
|
223
|
+
- AGENTS.md
|
|
224
|
+
`;
|
|
225
|
+
function migrateAeon(options = {}) {
|
|
226
|
+
const cwd = options.cwd ?? process.cwd();
|
|
227
|
+
const write = options.write ?? true;
|
|
228
|
+
const findings = walkHints(cwd);
|
|
229
|
+
const written = [];
|
|
230
|
+
if (write) {
|
|
231
|
+
const path = join2(cwd, "AEON_MIGRATION_CHECKLIST.md");
|
|
232
|
+
const findingsBlock = findings.length === 0 ? "\n## Scan results\n\nNo known local workarounds detected in the quick scan.\n" : `
|
|
233
|
+
## Scan results
|
|
234
|
+
|
|
235
|
+
${findings.map((f) => `- **${f.severity}** \`${f.id}\` (matched \`${f.pattern}\`): ${f.advice}`).join("\n")}
|
|
236
|
+
`;
|
|
237
|
+
writeFileSync2(path, `${CHECKLIST.trim()}
|
|
238
|
+
${findingsBlock}`);
|
|
239
|
+
written.push("write AEON_MIGRATION_CHECKLIST.md");
|
|
240
|
+
}
|
|
241
|
+
return { cwd, written, findings };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export {
|
|
245
|
+
initAeon,
|
|
246
|
+
migrateAeon
|
|
247
|
+
};
|
|
@@ -7,4 +7,20 @@ declare function initAeon(options?: InitOptions): {
|
|
|
7
7
|
written: string[];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
type MigrateOptions = {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
write?: boolean;
|
|
13
|
+
};
|
|
14
|
+
type Finding = {
|
|
15
|
+
id: string;
|
|
16
|
+
severity: 'replace' | 'optional' | 'info';
|
|
17
|
+
pattern: string;
|
|
18
|
+
advice: string;
|
|
19
|
+
};
|
|
20
|
+
declare function migrateAeon(options?: MigrateOptions): {
|
|
21
|
+
cwd: string;
|
|
22
|
+
written: string[];
|
|
23
|
+
findings: Finding[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { type InitOptions, type MigrateOptions, initAeon, migrateAeon };
|
package/packages/cli/src/bin.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { initAeon } from './init.js'
|
|
3
|
+
import { migrateAeon } from './migrate.js'
|
|
3
4
|
|
|
4
5
|
const args = process.argv.slice(2)
|
|
5
6
|
const cmd = args[0] ?? 'help'
|
|
6
7
|
const force = args.includes('--force') || args.includes('-f')
|
|
8
|
+
const checkOnly = args.includes('--check')
|
|
7
9
|
|
|
8
10
|
function help() {
|
|
9
11
|
console.log(`aeon-ui — AI-optimized CLI for Aeon UI
|
|
10
12
|
|
|
11
13
|
Usage:
|
|
12
14
|
npx aeon-ui init [--force]
|
|
15
|
+
npx aeon-ui migrate [--check]
|
|
13
16
|
|
|
14
17
|
Commands:
|
|
15
|
-
init
|
|
16
|
-
|
|
18
|
+
init Inject Cursor rules, JSON schemas, system prompt, and a starter component
|
|
19
|
+
migrate Scan for known workarounds and write AEON_MIGRATION_CHECKLIST.md
|
|
20
|
+
help Show this message
|
|
17
21
|
|
|
18
22
|
Options:
|
|
19
|
-
--force, -f Overwrite existing generated files
|
|
23
|
+
--force, -f Overwrite existing generated files (init)
|
|
24
|
+
--check Report findings only; do not write checklist (migrate)
|
|
20
25
|
`)
|
|
21
26
|
}
|
|
22
27
|
|
|
@@ -26,6 +31,19 @@ if (cmd === 'init') {
|
|
|
26
31
|
for (const line of result.written) console.log(` ${line}`)
|
|
27
32
|
console.log('\nNext: npm install aeon-ui-engine react react-dom xstate @xstate/react')
|
|
28
33
|
console.log('Docs: AEON_AI.md · paste aeon.cursorrules.md into your agent system prompt')
|
|
34
|
+
} else if (cmd === 'migrate') {
|
|
35
|
+
const result = migrateAeon({ write: !checkOnly })
|
|
36
|
+
console.log(`Aeon UI migrate → ${result.cwd}`)
|
|
37
|
+
for (const line of result.written) console.log(` ${line}`)
|
|
38
|
+
if (result.findings.length === 0) {
|
|
39
|
+
console.log(' (no known workarounds matched in quick scan)')
|
|
40
|
+
} else {
|
|
41
|
+
for (const f of result.findings) {
|
|
42
|
+
console.log(` [${f.severity}] ${f.id}: ${f.advice}`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
console.log('\nInstall: npm install aeon-ui-engine@^1.4.0 xstate @xstate/react')
|
|
46
|
+
console.log('Docs: https://aeon-ui.com · repo docs/MIGRATION.md')
|
|
29
47
|
} else {
|
|
30
48
|
help()
|
|
31
49
|
if (cmd !== 'help' && cmd !== '--help' && cmd !== '-h') {
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export type MigrateOptions = {
|
|
5
|
+
cwd?: string
|
|
6
|
+
write?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type Finding = {
|
|
10
|
+
id: string
|
|
11
|
+
severity: 'replace' | 'optional' | 'info'
|
|
12
|
+
pattern: string
|
|
13
|
+
advice: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const FINDINGS: Array<{
|
|
17
|
+
id: string
|
|
18
|
+
severity: Finding['severity']
|
|
19
|
+
patterns: string[]
|
|
20
|
+
advice: string
|
|
21
|
+
}> = [
|
|
22
|
+
{
|
|
23
|
+
id: 'preview-window-machine',
|
|
24
|
+
severity: 'replace',
|
|
25
|
+
patterns: ['preview-window-machine', 'previewWindowMachine'],
|
|
26
|
+
advice: 'Replace with RangeSlider from @aeon-ui/react or @aeon-ui/ui (rangeSliderMachine).',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'file-dropzone',
|
|
30
|
+
severity: 'replace',
|
|
31
|
+
patterns: ['file-dropzone-machine', 'fileDropzoneMachine', 'FileDropzone'],
|
|
32
|
+
advice: 'Replace with FileUpload compound (fileUploadMachine) — idle | dragging | rejected.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'sonner-bridge',
|
|
36
|
+
severity: 'replace',
|
|
37
|
+
patterns: ["from 'sonner'", 'from "sonner"', 'components/ui/sonner'],
|
|
38
|
+
advice: 'Use Toast.Provider + useToast().publish / dismiss (aeon-ui-engine ≥ 1.2).',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'manual-link-button',
|
|
42
|
+
severity: 'optional',
|
|
43
|
+
patterns: ['data-aeon-scope="button"', 'buttonVariants('],
|
|
44
|
+
advice:
|
|
45
|
+
'Prefer <Button.Root asChild><Link … /></Button.Root> instead of hand-rolled data-aeon-* on anchors.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'chakra',
|
|
49
|
+
severity: 'info',
|
|
50
|
+
patterns: ['@chakra-ui/react', '@ark-ui/react'],
|
|
51
|
+
advice:
|
|
52
|
+
'Migrate leaf → forms → overlays per docs/MIGRATION_FROM_ARK.md; see docs/MIGRATION.md for greenfield checklist.',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'alert-dialog-local',
|
|
56
|
+
severity: 'optional',
|
|
57
|
+
patterns: ['alertDialogMachine', 'role="alertdialog"'],
|
|
58
|
+
advice:
|
|
59
|
+
'Prefer Dialog/Prompt with dismissible=false for destructive confirms until AlertDialog ships.',
|
|
60
|
+
},
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
const CANDIDATES = [
|
|
64
|
+
'package.json',
|
|
65
|
+
'package-lock.json',
|
|
66
|
+
'pnpm-lock.yaml',
|
|
67
|
+
'lib/preview-window-machine.ts',
|
|
68
|
+
'lib/file-dropzone-machine.ts',
|
|
69
|
+
'components/file-dropzone.tsx',
|
|
70
|
+
'components/ui/sonner.tsx',
|
|
71
|
+
'components/ui/alert-dialog.tsx',
|
|
72
|
+
'components/ui/slider.tsx',
|
|
73
|
+
'components/ui/button.tsx',
|
|
74
|
+
'components/dual-login-buttons.tsx',
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
function walkHints(cwd: string): Finding[] {
|
|
78
|
+
const hits: Finding[] = []
|
|
79
|
+
let corpus = ''
|
|
80
|
+
|
|
81
|
+
for (const rel of CANDIDATES) {
|
|
82
|
+
const abs = join(cwd, rel)
|
|
83
|
+
if (!existsSync(abs)) continue
|
|
84
|
+
try {
|
|
85
|
+
corpus += `\n${rel}\n${readFileSync(abs, 'utf8')}`
|
|
86
|
+
} catch {
|
|
87
|
+
/* ignore unreadable */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const rule of FINDINGS) {
|
|
92
|
+
const matched = rule.patterns.find((p) => corpus.includes(p))
|
|
93
|
+
if (matched) {
|
|
94
|
+
hits.push({
|
|
95
|
+
id: rule.id,
|
|
96
|
+
severity: rule.severity,
|
|
97
|
+
pattern: matched,
|
|
98
|
+
advice: rule.advice,
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return hits
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const CHECKLIST = `# Aeon migration checklist
|
|
107
|
+
|
|
108
|
+
Generated by \`npx aeon-ui migrate\`.
|
|
109
|
+
|
|
110
|
+
## Install
|
|
111
|
+
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
npm install aeon-ui-engine@^1.4.0 react react-dom xstate @xstate/react
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
\`\`\`ts
|
|
117
|
+
import 'aeon-ui-engine/aeon.css'
|
|
118
|
+
\`\`\`
|
|
119
|
+
|
|
120
|
+
## Agent setup
|
|
121
|
+
|
|
122
|
+
\`\`\`bash
|
|
123
|
+
npx aeon-ui init
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
Paste \`aeon.cursorrules.md\` into Cursor rules. Keep domain machines in the app; use Aeon for chrome + interactive primitives.
|
|
127
|
+
|
|
128
|
+
## Statechart-first rule
|
|
129
|
+
|
|
130
|
+
1. Model interaction with an XState machine (or reuse Aeon machines).
|
|
131
|
+
2. Project \`snapshot\` → \`data-aeon-state\` / compound parts.
|
|
132
|
+
3. Do not invent parallel booleans for chart-owned concerns.
|
|
133
|
+
|
|
134
|
+
## New primitives (1.4+)
|
|
135
|
+
|
|
136
|
+
| Need | Use |
|
|
137
|
+
|------|-----|
|
|
138
|
+
| Two-thumb range | \`RangeSlider\` + \`rangeSliderMachine\` |
|
|
139
|
+
| Link styled as button | \`<Button.Root asChild><Link/></Button.Root>\` |
|
|
140
|
+
| Drag-drop file surface | \`FileUpload\` + \`fileUploadMachine\` |
|
|
141
|
+
| Toast | \`Toast.Provider\` + \`useToast()\` |
|
|
142
|
+
| Confirm sheet | \`Prompt\` / \`Dialog\` |
|
|
143
|
+
|
|
144
|
+
## Docs
|
|
145
|
+
|
|
146
|
+
- docs/MIGRATION.md (in aeon-ui-engine / AeonUI repo)
|
|
147
|
+
- docs/MIGRATION_FROM_ARK.md
|
|
148
|
+
- AGENTS.md
|
|
149
|
+
`
|
|
150
|
+
|
|
151
|
+
export function migrateAeon(options: MigrateOptions = {}) {
|
|
152
|
+
const cwd = options.cwd ?? process.cwd()
|
|
153
|
+
const write = options.write ?? true
|
|
154
|
+
const findings = walkHints(cwd)
|
|
155
|
+
const written: string[] = []
|
|
156
|
+
|
|
157
|
+
if (write) {
|
|
158
|
+
const path = join(cwd, 'AEON_MIGRATION_CHECKLIST.md')
|
|
159
|
+
const findingsBlock =
|
|
160
|
+
findings.length === 0
|
|
161
|
+
? '\n## Scan results\n\nNo known local workarounds detected in the quick scan.\n'
|
|
162
|
+
: `\n## Scan results\n\n${findings
|
|
163
|
+
.map((f) => `- **${f.severity}** \`${f.id}\` (matched \`${f.pattern}\`): ${f.advice}`)
|
|
164
|
+
.join('\n')}\n`
|
|
165
|
+
writeFileSync(path, `${CHECKLIST.trim()}\n${findingsBlock}`)
|
|
166
|
+
written.push('write AEON_MIGRATION_CHECKLIST.md')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { cwd, written, findings }
|
|
170
|
+
}
|