@aex.is/zero 0.1.4 → 0.1.6
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/dist/engine/scaffold.js +3 -1
- package/dist/engine/templates.js +2 -2
- package/package.json +2 -2
- package/dist/ui/App.js +0 -75
- package/dist/ui/components/SelectList.js +0 -67
- package/dist/ui/screens/Confirm.js +0 -22
- package/dist/ui/screens/DomainPrompt.js +0 -11
- package/dist/ui/screens/FrameworkSelect.js +0 -12
- package/dist/ui/screens/Intro.js +0 -18
- package/dist/ui/screens/ModuleSelect.js +0 -12
- package/dist/ui/screens/NamePrompt.js +0 -18
package/dist/engine/scaffold.js
CHANGED
|
@@ -41,7 +41,9 @@ async function ensureEmptyTargetDir(targetDir) {
|
|
|
41
41
|
throw new Error('Target path exists and is not a directory.');
|
|
42
42
|
}
|
|
43
43
|
const entries = await fs.readdir(targetDir);
|
|
44
|
-
|
|
44
|
+
const allowed = new Set(['.git', '.gitignore', '.gitkeep']);
|
|
45
|
+
const remaining = entries.filter((entry) => !allowed.has(entry));
|
|
46
|
+
if (remaining.length > 0) {
|
|
45
47
|
throw new Error('Target directory is not empty.');
|
|
46
48
|
}
|
|
47
49
|
}
|
package/dist/engine/templates.js
CHANGED
|
@@ -134,7 +134,7 @@ export default function RootLayout({
|
|
|
134
134
|
<div className="flex min-h-screen flex-col">
|
|
135
135
|
<SiteHeader appName="${escapeTemplate(appName)}" />
|
|
136
136
|
<main className="flex-1">{children}</main>
|
|
137
|
-
<SiteFooter
|
|
137
|
+
<SiteFooter />
|
|
138
138
|
</div>
|
|
139
139
|
</body>
|
|
140
140
|
</html>
|
|
@@ -224,7 +224,7 @@ function nextFooterTemplate(domain) {
|
|
|
224
224
|
const domainLabel = escapeTemplate(domain).trim().length > 0
|
|
225
225
|
? `Domain: ${escapeTemplate(domain)}`
|
|
226
226
|
: 'Domain: not set';
|
|
227
|
-
return `export function SiteFooter(
|
|
227
|
+
return `export function SiteFooter() {
|
|
228
228
|
return (
|
|
229
229
|
<footer className=\"border-t border-[var(--fg)]\">
|
|
230
230
|
<div className=\"mx-auto flex w-full max-w-4xl flex-col gap-2 px-6 py-4 text-xs\">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aex.is/zero",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Aexis Zero scaffolding CLI",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsc -p tsconfig.json",
|
|
20
|
+
"build": "node scripts/clean-dist.cjs && tsc -p tsconfig.json",
|
|
21
21
|
"dev": "bun run src/index.ts",
|
|
22
22
|
"start": "node dist/index.js",
|
|
23
23
|
"prepublishOnly": "npm run build"
|
package/dist/ui/App.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useRef, useState } from 'react';
|
|
3
|
-
import { Box, Text, useApp } from 'ink';
|
|
4
|
-
import { Intro } from './screens/Intro.js';
|
|
5
|
-
import { NamePrompt } from './screens/NamePrompt.js';
|
|
6
|
-
import { DomainPrompt } from './screens/DomainPrompt.js';
|
|
7
|
-
import { FrameworkSelect } from './screens/FrameworkSelect.js';
|
|
8
|
-
import { ModuleSelect } from './screens/ModuleSelect.js';
|
|
9
|
-
import { Confirm } from './screens/Confirm.js';
|
|
10
|
-
export function App({ onComplete }) {
|
|
11
|
-
const { exit } = useApp();
|
|
12
|
-
const [step, setStep] = useState('intro');
|
|
13
|
-
const [resumeStep, setResumeStep] = useState(null);
|
|
14
|
-
const [name, setName] = useState('');
|
|
15
|
-
const [domain, setDomain] = useState('');
|
|
16
|
-
const [framework, setFramework] = useState('nextjs');
|
|
17
|
-
const [modules, setModules] = useState([]);
|
|
18
|
-
const completedRef = useRef(false);
|
|
19
|
-
const finish = useCallback((config) => {
|
|
20
|
-
if (completedRef.current) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
completedRef.current = true;
|
|
24
|
-
onComplete(config);
|
|
25
|
-
exit();
|
|
26
|
-
}, [exit, onComplete]);
|
|
27
|
-
const goNext = useCallback((next) => {
|
|
28
|
-
if (resumeStep) {
|
|
29
|
-
setStep(resumeStep);
|
|
30
|
-
setResumeStep(null);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
setStep(next);
|
|
34
|
-
}, [resumeStep]);
|
|
35
|
-
const handleConfirmAction = useCallback((action) => {
|
|
36
|
-
switch (action) {
|
|
37
|
-
case 'continue':
|
|
38
|
-
finish({
|
|
39
|
-
appName: name,
|
|
40
|
-
domain,
|
|
41
|
-
framework,
|
|
42
|
-
modules
|
|
43
|
-
});
|
|
44
|
-
return;
|
|
45
|
-
case 'cancel':
|
|
46
|
-
finish(null);
|
|
47
|
-
return;
|
|
48
|
-
case 'edit-name':
|
|
49
|
-
setResumeStep('confirm');
|
|
50
|
-
setStep('name');
|
|
51
|
-
return;
|
|
52
|
-
case 'edit-domain':
|
|
53
|
-
setResumeStep('confirm');
|
|
54
|
-
setStep('domain');
|
|
55
|
-
return;
|
|
56
|
-
case 'edit-framework':
|
|
57
|
-
setResumeStep('confirm');
|
|
58
|
-
setStep('framework');
|
|
59
|
-
return;
|
|
60
|
-
case 'edit-modules':
|
|
61
|
-
setResumeStep('confirm');
|
|
62
|
-
setStep('modules');
|
|
63
|
-
return;
|
|
64
|
-
default:
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
}, [domain, finish, framework, modules, name]);
|
|
68
|
-
return (_jsxs(Box, { flexDirection: "column", children: [step === 'intro' ? null : (_jsx(Text, { color: "cyan", children: "Aexis Zero" })), step === 'intro' ? (_jsx(Intro, { onContinue: () => setStep('name') })) : null, step === 'name' ? (_jsx(NamePrompt, { initialValue: name, onSubmit: (value) => {
|
|
69
|
-
setName(value);
|
|
70
|
-
goNext('domain');
|
|
71
|
-
} })) : null, step === 'domain' ? (_jsx(DomainPrompt, { initialValue: domain, onSubmit: (value) => {
|
|
72
|
-
setDomain(value);
|
|
73
|
-
goNext('framework');
|
|
74
|
-
} })) : null, step === 'framework' ? (_jsx(FrameworkSelect, { value: framework, onChange: setFramework, onConfirm: () => goNext('modules') })) : null, step === 'modules' ? (_jsx(ModuleSelect, { value: modules, onChange: setModules, onConfirm: () => goNext('confirm') })) : null, step === 'confirm' ? (_jsx(Confirm, { name: name, domain: domain, framework: framework, modules: modules, onAction: handleConfirmAction })) : null] }));
|
|
75
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
-
import { Box, Text, useInput } from 'ink';
|
|
4
|
-
export function SelectList({ items, selectedIds, onChange, onSubmit, multi = false, hint }) {
|
|
5
|
-
const [index, setIndex] = useState(0);
|
|
6
|
-
const selectedSet = useMemo(() => new Set(selectedIds), [selectedIds]);
|
|
7
|
-
const move = useCallback((delta) => {
|
|
8
|
-
setIndex((current) => {
|
|
9
|
-
const next = current + delta;
|
|
10
|
-
if (next < 0) {
|
|
11
|
-
return items.length - 1;
|
|
12
|
-
}
|
|
13
|
-
if (next >= items.length) {
|
|
14
|
-
return 0;
|
|
15
|
-
}
|
|
16
|
-
return next;
|
|
17
|
-
});
|
|
18
|
-
}, [items.length]);
|
|
19
|
-
const toggle = useCallback((itemId) => {
|
|
20
|
-
if (multi) {
|
|
21
|
-
const next = new Set(selectedSet);
|
|
22
|
-
if (next.has(itemId)) {
|
|
23
|
-
next.delete(itemId);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
next.add(itemId);
|
|
27
|
-
}
|
|
28
|
-
onChange(Array.from(next));
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
onChange([itemId]);
|
|
32
|
-
}
|
|
33
|
-
}, [multi, onChange, selectedSet]);
|
|
34
|
-
useInput((input, key) => {
|
|
35
|
-
if (key.upArrow) {
|
|
36
|
-
move(-1);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (key.downArrow) {
|
|
40
|
-
move(1);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (input === ' ') {
|
|
44
|
-
const item = items[index];
|
|
45
|
-
if (item) {
|
|
46
|
-
toggle(item.id);
|
|
47
|
-
}
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (key.return) {
|
|
51
|
-
onSubmit();
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", children: items.map((item, idx) => {
|
|
55
|
-
const isSelected = selectedSet.has(item.id);
|
|
56
|
-
const isActive = idx === index;
|
|
57
|
-
const prefix = isActive ? '>' : ' ';
|
|
58
|
-
const marker = multi
|
|
59
|
-
? isSelected
|
|
60
|
-
? '[x]'
|
|
61
|
-
: '[ ]'
|
|
62
|
-
: isSelected
|
|
63
|
-
? '(x)'
|
|
64
|
-
: '( )';
|
|
65
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: isActive ? 'cyan' : undefined, children: [prefix, " ", marker, " ", item.label] }), item.description ? (_jsxs(Text, { color: "gray", children: [" ", item.description] })) : null] }, item.id));
|
|
66
|
-
}) }), hint ? _jsx(Text, { color: "gray", children: hint }) : null] }));
|
|
67
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
import { SelectList } from '../components/SelectList.js';
|
|
5
|
-
import { frameworks } from '../../config/frameworks.js';
|
|
6
|
-
import { modules } from '../../config/modules.js';
|
|
7
|
-
const actionItems = [
|
|
8
|
-
{ id: 'continue', label: 'Continue' },
|
|
9
|
-
{ id: 'edit-name', label: 'Edit name' },
|
|
10
|
-
{ id: 'edit-domain', label: 'Edit domain' },
|
|
11
|
-
{ id: 'edit-framework', label: 'Edit framework' },
|
|
12
|
-
{ id: 'edit-modules', label: 'Edit modules' },
|
|
13
|
-
{ id: 'cancel', label: 'Cancel' }
|
|
14
|
-
];
|
|
15
|
-
export function Confirm({ name, domain, framework, modules: selectedModules, onAction }) {
|
|
16
|
-
const [selection, setSelection] = useState('continue');
|
|
17
|
-
const frameworkLabel = frameworks.find((item) => item.id === framework)?.label ?? framework;
|
|
18
|
-
const moduleLabels = selectedModules
|
|
19
|
-
.map((id) => modules.find((item) => item.id === id)?.label ?? id)
|
|
20
|
-
.join(', ');
|
|
21
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Confirm" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["App name: ", name] }), _jsxs(Text, { children: ["Domain: ", domain || 'None'] }), _jsxs(Text, { children: ["Framework: ", frameworkLabel] }), _jsxs(Text, { children: ["Modules: ", moduleLabels || 'None'] })] }), _jsx(Box, { marginTop: 1, children: _jsx(SelectList, { items: actionItems, selectedIds: [selection], onChange: (next) => setSelection(next[0]), onSubmit: () => onAction(selection), multi: false, hint: "Select an action and press Enter." }) })] }));
|
|
22
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
import TextInput from 'ink-text-input';
|
|
5
|
-
export function DomainPrompt({ initialValue, onSubmit }) {
|
|
6
|
-
const [value, setValue] = useState(initialValue);
|
|
7
|
-
const handleSubmit = () => {
|
|
8
|
-
onSubmit(value.trim());
|
|
9
|
-
};
|
|
10
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Domain (optional)" }), _jsx(Text, { color: "gray", children: "Press Enter to continue or leave blank." }), _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: "example.com" })] }));
|
|
11
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { SelectList } from '../components/SelectList.js';
|
|
4
|
-
import { frameworks } from '../../config/frameworks.js';
|
|
5
|
-
export function FrameworkSelect({ value, onChange, onConfirm }) {
|
|
6
|
-
const items = frameworks.map((framework) => ({
|
|
7
|
-
id: framework.id,
|
|
8
|
-
label: framework.label,
|
|
9
|
-
description: framework.description
|
|
10
|
-
}));
|
|
11
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Framework" }), _jsx(Text, { color: "gray", children: "Use arrows to move, space to select, Enter to confirm." }), _jsx(SelectList, { items: items, selectedIds: [value], onChange: (next) => onChange(next[0]), onSubmit: onConfirm, multi: false, hint: "( ) radio select" })] }));
|
|
12
|
-
}
|
package/dist/ui/screens/Intro.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useInput } from 'ink';
|
|
3
|
-
const introArt = [
|
|
4
|
-
' _____',
|
|
5
|
-
' / ___ \\ ',
|
|
6
|
-
' / / _ \\ \\ ',
|
|
7
|
-
' | |/ /| |',
|
|
8
|
-
' \\ \\_/ / /',
|
|
9
|
-
' \\___/_/'
|
|
10
|
-
].join('\n');
|
|
11
|
-
export function Intro({ onContinue }) {
|
|
12
|
-
useInput((input, key) => {
|
|
13
|
-
if (key.return || input === ' ') {
|
|
14
|
-
onContinue();
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: introArt }), _jsx(Text, { color: "cyan", children: "Aexis Zero" }), _jsx(Text, { color: "gray", children: "Press Enter to begin." })] }));
|
|
18
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { SelectList } from '../components/SelectList.js';
|
|
4
|
-
import { modules } from '../../config/modules.js';
|
|
5
|
-
export function ModuleSelect({ value, onChange, onConfirm }) {
|
|
6
|
-
const items = modules.map((module) => ({
|
|
7
|
-
id: module.id,
|
|
8
|
-
label: module.label,
|
|
9
|
-
description: module.description
|
|
10
|
-
}));
|
|
11
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "Modules" }), _jsx(Text, { color: "gray", children: "Use arrows to move, space to toggle, Enter to confirm." }), _jsx(SelectList, { items: items, selectedIds: value, onChange: (next) => onChange(next), onSubmit: onConfirm, multi: true, hint: "[ ] multi-select" })] }));
|
|
12
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
import TextInput from 'ink-text-input';
|
|
5
|
-
export function NamePrompt({ initialValue, onSubmit }) {
|
|
6
|
-
const [value, setValue] = useState(initialValue);
|
|
7
|
-
const [error, setError] = useState('');
|
|
8
|
-
const handleSubmit = () => {
|
|
9
|
-
const trimmed = value.trim();
|
|
10
|
-
if (!trimmed) {
|
|
11
|
-
setError('App name is required.');
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
setError('');
|
|
15
|
-
onSubmit(trimmed);
|
|
16
|
-
};
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", children: "App name" }), _jsx(Text, { color: "gray", children: "Required. Press Enter to continue." }), _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: "my-app" }), error ? _jsx(Text, { color: "red", children: error }) : null] }));
|
|
18
|
-
}
|