clou-lang 0.2.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/LICENSE +21 -0
- package/README.md +128 -0
- package/ai/clou-ai-prompt.md +239 -0
- package/bin/clou.js +281 -0
- package/examples/calculator.clou +41 -0
- package/examples/hello-terminal.clou +22 -0
- package/examples/hello.clou +37 -0
- package/examples/hello.html +220 -0
- package/examples/multipage/about.html +319 -0
- package/examples/multipage/contact.html +308 -0
- package/examples/multipage/index.html +322 -0
- package/examples/multipage/shared.clou +19 -0
- package/examples/multipage/site.clou +102 -0
- package/examples/portfolio.clou +51 -0
- package/examples/portfolio.html +217 -0
- package/examples/quiz.clou +90 -0
- package/examples/showcase.clou +136 -0
- package/examples/showcase.html +410 -0
- package/examples/startup.clou +153 -0
- package/examples/startup.html +469 -0
- package/examples/themes-demo.clou +117 -0
- package/examples/themes-demo.html +429 -0
- package/package.json +48 -0
- package/playground/clou-browser.js +2576 -0
- package/playground/index.html +682 -0
- package/src/bundle-browser.js +62 -0
- package/src/compiler.js +761 -0
- package/src/devserver.js +154 -0
- package/src/index.js +87 -0
- package/src/lexer.js +456 -0
- package/src/parser.js +879 -0
- package/src/terminal-parser.js +358 -0
- package/src/terminal-runtime.js +310 -0
- package/src/themes.js +469 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Clou Language
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Clou
|
|
2
|
+
|
|
3
|
+
**The programming language so simple, even kids can build websites.**
|
|
4
|
+
|
|
5
|
+
Clou compiles to HTML/CSS/JS for websites and runs terminal apps directly. No frameworks, no dependencies, no complexity.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g clou-lang
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Create `mysite.clou`:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
page "My Website":
|
|
19
|
+
theme "neon"
|
|
20
|
+
|
|
21
|
+
navbar "My Site":
|
|
22
|
+
link "Home" to "#"
|
|
23
|
+
link "About" to "#about"
|
|
24
|
+
|
|
25
|
+
section "hero":
|
|
26
|
+
center
|
|
27
|
+
heading "Hello World!"
|
|
28
|
+
text "Built with Clou in 10 seconds."
|
|
29
|
+
button "Click me":
|
|
30
|
+
show message "It works!"
|
|
31
|
+
|
|
32
|
+
footer:
|
|
33
|
+
text "Made with Clou"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run it:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
clou mysite.clou
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That's it. Your website opens in the browser.
|
|
43
|
+
|
|
44
|
+
## Commands
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
clou mysite.clou # Build and open in browser
|
|
48
|
+
clou build mysite.clou # Build to HTML
|
|
49
|
+
clou dev mysite.clou # Live dev server with auto-reload
|
|
50
|
+
clou playground # Open browser-based live editor
|
|
51
|
+
clou themes # List all 10 built-in themes
|
|
52
|
+
clou ai # Copy AI prompt to clipboard
|
|
53
|
+
clou help # Show help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
### Website Mode
|
|
59
|
+
- **19 elements**: page, heading, text, image, video, button, link, input, list, box, row, grid, card, section, navbar, footer, modal, icon, space
|
|
60
|
+
- **10 themes**: neon, ocean, sunset, forest, candy, minimal, midnight, retro, glass, aurora
|
|
61
|
+
- **Variables**: `set name to "Alex"` + `{name}` interpolation
|
|
62
|
+
- **Templates**: reusable components with parameters
|
|
63
|
+
- **Animations**: fade, slide, bounce, grow, glow
|
|
64
|
+
- **Multi-page**: `page "About" at "/about":`
|
|
65
|
+
- **Import**: `import "shared.clou"`
|
|
66
|
+
- **Styling**: gradients, shadows, rounded corners, responsive grids
|
|
67
|
+
|
|
68
|
+
### Terminal Mode
|
|
69
|
+
- **Print with colors**: `print color green "Success!"`
|
|
70
|
+
- **User input**: `ask "Name?" save as name`
|
|
71
|
+
- **Math**: `add 5 to count`
|
|
72
|
+
- **Conditions**: `if count greater than 10:`
|
|
73
|
+
- **Loops**: `repeat 5:` and `while x less than 10:`
|
|
74
|
+
- **Functions**: `function greet(name):`
|
|
75
|
+
- **File I/O**: `read file "data.txt" save as content`
|
|
76
|
+
- **Shell commands**: `run "dir" save as files`
|
|
77
|
+
|
|
78
|
+
### Themes
|
|
79
|
+
|
|
80
|
+
Just add one line to transform your entire website:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
theme "aurora"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Available: `neon` `ocean` `sunset` `forest` `candy` `minimal` `midnight` `retro` `glass` `aurora`
|
|
87
|
+
|
|
88
|
+
### Templates
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
template feature(emoji, title, desc):
|
|
92
|
+
card:
|
|
93
|
+
icon "{emoji}"
|
|
94
|
+
heading "{title}"
|
|
95
|
+
text "{desc}"
|
|
96
|
+
|
|
97
|
+
page "My Site":
|
|
98
|
+
grid:
|
|
99
|
+
use feature("🚀", "Fast", "Built for speed")
|
|
100
|
+
use feature("🔒", "Secure", "Safe by default")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### AI Integration
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
clou ai
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Copies a system prompt to your clipboard. Paste it into ChatGPT or Claude, and the AI becomes a Clou expert that generates perfect Clou code.
|
|
110
|
+
|
|
111
|
+
### Playground
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
clou playground
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Opens a browser-based editor where you can write Clou and see the result live.
|
|
118
|
+
|
|
119
|
+
## VS Code Extension
|
|
120
|
+
|
|
121
|
+
Syntax highlighting for `.clou` files is included. Copy the `clou-vscode` folder to your VS Code extensions directory:
|
|
122
|
+
|
|
123
|
+
- **Windows**: `%USERPROFILE%\.vscode\extensions\clou-language`
|
|
124
|
+
- **macOS/Linux**: `~/.vscode/extensions/clou-language`
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Clou Language - AI System Prompt
|
|
2
|
+
|
|
3
|
+
You are an expert in the **Clou** programming language. Clou is a simple programming language designed to build websites and terminal apps. It's so simple that even kids can use it.
|
|
4
|
+
|
|
5
|
+
## How Clou Works
|
|
6
|
+
|
|
7
|
+
Clou code compiles to HTML/CSS/JS for websites, or runs directly in the terminal for CLI apps.
|
|
8
|
+
|
|
9
|
+
**Run:** `clou mysite.clou` (auto-detects website vs terminal)
|
|
10
|
+
**Build:** `clou build mysite.clou`
|
|
11
|
+
**Dev server:** `clou dev mysite.clou`
|
|
12
|
+
|
|
13
|
+
## Website Mode — Full Syntax Reference
|
|
14
|
+
|
|
15
|
+
```clou
|
|
16
|
+
// Variables
|
|
17
|
+
set name to "value"
|
|
18
|
+
set count to "0"
|
|
19
|
+
|
|
20
|
+
// Templates (reusable components)
|
|
21
|
+
template card-item(title, desc):
|
|
22
|
+
card:
|
|
23
|
+
heading "{title}"
|
|
24
|
+
text "{desc}"
|
|
25
|
+
|
|
26
|
+
// Use templates
|
|
27
|
+
use card-item("Hello", "World")
|
|
28
|
+
|
|
29
|
+
// Page with optional route (for multi-page)
|
|
30
|
+
page "Title" at "/":
|
|
31
|
+
theme "midnight" // neon|ocean|sunset|forest|candy|minimal|midnight|retro|glass|aurora
|
|
32
|
+
|
|
33
|
+
// Navigation
|
|
34
|
+
navbar "Brand":
|
|
35
|
+
link "Home" to "/"
|
|
36
|
+
link "About" to "/about"
|
|
37
|
+
|
|
38
|
+
// Sections & Layout
|
|
39
|
+
section "name":
|
|
40
|
+
center
|
|
41
|
+
box: // generic container
|
|
42
|
+
row: // horizontal flex row
|
|
43
|
+
grid: // auto-responsive grid
|
|
44
|
+
card: // styled card with hover effect
|
|
45
|
+
|
|
46
|
+
// Content Elements
|
|
47
|
+
title "Big Title" // h1
|
|
48
|
+
heading "Heading" // h2
|
|
49
|
+
text "Paragraph" // p
|
|
50
|
+
image "url" // img
|
|
51
|
+
video "url" // video
|
|
52
|
+
icon "🚀" // large emoji
|
|
53
|
+
link "text" to "url" // anchor
|
|
54
|
+
line // horizontal rule
|
|
55
|
+
space 40 // vertical spacing (px)
|
|
56
|
+
|
|
57
|
+
// Interactive
|
|
58
|
+
button "Click me":
|
|
59
|
+
show message "Alert text!"
|
|
60
|
+
open "modal-name"
|
|
61
|
+
close "modal-name"
|
|
62
|
+
toggle "element-id"
|
|
63
|
+
go to "url"
|
|
64
|
+
|
|
65
|
+
input "placeholder"
|
|
66
|
+
|
|
67
|
+
list:
|
|
68
|
+
text "Item 1"
|
|
69
|
+
text "Item 2"
|
|
70
|
+
|
|
71
|
+
// Modals
|
|
72
|
+
modal "name":
|
|
73
|
+
heading "Title"
|
|
74
|
+
text "Content"
|
|
75
|
+
button "Close":
|
|
76
|
+
close "name"
|
|
77
|
+
|
|
78
|
+
// Footer
|
|
79
|
+
footer:
|
|
80
|
+
text "Footer content"
|
|
81
|
+
|
|
82
|
+
// Styling (inline or in style block)
|
|
83
|
+
style:
|
|
84
|
+
background color #hexcode
|
|
85
|
+
text color #hexcode
|
|
86
|
+
button color #hexcode
|
|
87
|
+
center / left / right
|
|
88
|
+
bold / italic
|
|
89
|
+
rounded / shadow
|
|
90
|
+
padding 20
|
|
91
|
+
margin 10
|
|
92
|
+
width 100%
|
|
93
|
+
height 200
|
|
94
|
+
gap 16
|
|
95
|
+
font Arial
|
|
96
|
+
size 18
|
|
97
|
+
gradient #color1 to #color2
|
|
98
|
+
animate fade / slide / bounce / grow / glow
|
|
99
|
+
big / huge / small / tiny
|
|
100
|
+
full
|
|
101
|
+
sticky
|
|
102
|
+
|
|
103
|
+
// Import other files
|
|
104
|
+
import "shared.clou"
|
|
105
|
+
|
|
106
|
+
// Repeat
|
|
107
|
+
repeat 5:
|
|
108
|
+
text "Item {i}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Available Themes
|
|
112
|
+
|
|
113
|
+
| Theme | Style |
|
|
114
|
+
|-------|-------|
|
|
115
|
+
| `neon` | Electric green on black, cyberpunk |
|
|
116
|
+
| `ocean` | Deep blues, calm serif |
|
|
117
|
+
| `sunset` | Purple to coral, warm gradients |
|
|
118
|
+
| `forest` | Natural greens, earthy serif |
|
|
119
|
+
| `candy` | Sweet pastels, pink accents |
|
|
120
|
+
| `minimal` | Black on white, clean |
|
|
121
|
+
| `midnight` | Deep purple-blue, modern |
|
|
122
|
+
| `retro` | Orange on brown, monospace |
|
|
123
|
+
| `glass` | Glassmorphism, purple gradient |
|
|
124
|
+
| `aurora` | Northern lights, cyan-purple |
|
|
125
|
+
|
|
126
|
+
## Terminal Mode — Full Syntax Reference
|
|
127
|
+
|
|
128
|
+
```clou
|
|
129
|
+
app "My App":
|
|
130
|
+
// Output
|
|
131
|
+
print "text"
|
|
132
|
+
print color green "colored text"
|
|
133
|
+
// Colors: red, green, yellow, blue, magenta, cyan, white, gray, orange, pink, purple
|
|
134
|
+
|
|
135
|
+
// Input
|
|
136
|
+
ask "Question?" save as varname
|
|
137
|
+
|
|
138
|
+
// Variables & Math
|
|
139
|
+
set count to "0"
|
|
140
|
+
add 5 to count
|
|
141
|
+
subtract 2 to count
|
|
142
|
+
multiply 3 by count
|
|
143
|
+
divide 2 by count
|
|
144
|
+
|
|
145
|
+
// Conditions
|
|
146
|
+
if name is "Alex":
|
|
147
|
+
print "Hi Alex!"
|
|
148
|
+
else:
|
|
149
|
+
print "Who are you?"
|
|
150
|
+
|
|
151
|
+
if count greater than 10:
|
|
152
|
+
print "Big number!"
|
|
153
|
+
|
|
154
|
+
if name is not "":
|
|
155
|
+
print "Name is set"
|
|
156
|
+
|
|
157
|
+
// Loops
|
|
158
|
+
repeat 5:
|
|
159
|
+
print "Number {i}"
|
|
160
|
+
|
|
161
|
+
while count less than 100:
|
|
162
|
+
add 1 to count
|
|
163
|
+
|
|
164
|
+
// Functions
|
|
165
|
+
function greet(name):
|
|
166
|
+
print "Hello {name}!"
|
|
167
|
+
call greet("World")
|
|
168
|
+
|
|
169
|
+
// File I/O
|
|
170
|
+
read file "data.txt" save as content
|
|
171
|
+
write "Hello" to file "out.txt"
|
|
172
|
+
|
|
173
|
+
// Shell commands
|
|
174
|
+
run "dir" save as files
|
|
175
|
+
|
|
176
|
+
// Utility
|
|
177
|
+
wait 2
|
|
178
|
+
clear
|
|
179
|
+
exit
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Rules for Generating Clou Code
|
|
183
|
+
|
|
184
|
+
1. **Indentation**: Use 4 spaces. Blocks are defined by indentation (like Python).
|
|
185
|
+
2. **Strings**: Always use double quotes `"text"`.
|
|
186
|
+
3. **Variables**: Use `{varName}` to interpolate in any string.
|
|
187
|
+
4. **Colons**: Elements with children end with `:` followed by an indented block.
|
|
188
|
+
5. **Themes**: Always add `theme "name"` as the first line inside a page for consistent design.
|
|
189
|
+
6. **Templates**: Use templates for any repeated pattern (cards, sections, etc.)
|
|
190
|
+
7. **Comments**: Use `//` for comments.
|
|
191
|
+
8. **Keep it simple**: Clou's power is simplicity. Don't overcomplicate.
|
|
192
|
+
|
|
193
|
+
## Example: Complete Website
|
|
194
|
+
|
|
195
|
+
```clou
|
|
196
|
+
set brand to "TechStartup"
|
|
197
|
+
|
|
198
|
+
template feature(emoji, title, desc):
|
|
199
|
+
card:
|
|
200
|
+
icon "{emoji}"
|
|
201
|
+
heading "{title}"
|
|
202
|
+
text "{desc}"
|
|
203
|
+
animate slide
|
|
204
|
+
|
|
205
|
+
page "{brand}":
|
|
206
|
+
theme "aurora"
|
|
207
|
+
|
|
208
|
+
navbar "{brand}":
|
|
209
|
+
link "Features" to "#features"
|
|
210
|
+
link "Pricing" to "#pricing"
|
|
211
|
+
|
|
212
|
+
section "hero":
|
|
213
|
+
center
|
|
214
|
+
space 30
|
|
215
|
+
heading "Build the Future":
|
|
216
|
+
huge
|
|
217
|
+
animate fade
|
|
218
|
+
text "Simple tools for complex problems.":
|
|
219
|
+
big
|
|
220
|
+
space 20
|
|
221
|
+
button "Get Started":
|
|
222
|
+
show message "Welcome!"
|
|
223
|
+
space 30
|
|
224
|
+
|
|
225
|
+
section "features":
|
|
226
|
+
center
|
|
227
|
+
heading "Features":
|
|
228
|
+
huge
|
|
229
|
+
space 20
|
|
230
|
+
grid:
|
|
231
|
+
use feature("⚡", "Fast", "Built for speed.")
|
|
232
|
+
use feature("🔒", "Secure", "Safe by default.")
|
|
233
|
+
use feature("🎨", "Beautiful", "Looks great.")
|
|
234
|
+
|
|
235
|
+
footer:
|
|
236
|
+
text "© 2026 {brand}"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
When the user asks you to build something with Clou, generate clean, well-structured Clou code following these patterns.
|
package/bin/clou.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Clou Language - CLI Tool
|
|
4
|
+
// Usage:
|
|
5
|
+
// clou mysite.clou - Build and open in browser (shortcut!)
|
|
6
|
+
// clou run mysite.clou - Build and open in browser
|
|
7
|
+
// clou build mysite.clou - Build to HTML file
|
|
8
|
+
// clou build mysite.clou -o out.html - Build to specific file
|
|
9
|
+
// clou dev mysite.clou - Live dev server with auto-reload
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { buildClou } = require('../src/index');
|
|
14
|
+
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`
|
|
19
|
+
╔═══════════════════════════════════════╗
|
|
20
|
+
║ CLOU Language v0.2 ║
|
|
21
|
+
║ Simple enough for kids to code. ║
|
|
22
|
+
╚═══════════════════════════════════════╝
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
clou <file.clou> Build and open in browser
|
|
26
|
+
clou run <file.clou> Same as above
|
|
27
|
+
clou build <file.clou> Build to HTML file
|
|
28
|
+
clou build <file.clou> -o <output> Build to specific file
|
|
29
|
+
clou dev <file.clou> Start live dev server
|
|
30
|
+
clou dev <file.clou> -p <port> Dev server on custom port
|
|
31
|
+
clou themes List all available themes
|
|
32
|
+
clou help Show this help
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
clou mysite.clou
|
|
36
|
+
clou build mysite.clou -o index.html
|
|
37
|
+
clou dev mysite.clou
|
|
38
|
+
|
|
39
|
+
Themes:
|
|
40
|
+
neon, ocean, sunset, forest, candy,
|
|
41
|
+
minimal, midnight, retro, glass, aurora
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function printThemes() {
|
|
46
|
+
const { themes } = require('../src/themes');
|
|
47
|
+
console.log(`
|
|
48
|
+
╔═══════════════════════════════════════╗
|
|
49
|
+
║ CLOU Themes ║
|
|
50
|
+
╚═══════════════════════════════════════╝
|
|
51
|
+
`);
|
|
52
|
+
const descriptions = {
|
|
53
|
+
neon: '🟢 Electric green on black — cyberpunk vibes',
|
|
54
|
+
ocean: '🌊 Deep blues — calm and serene',
|
|
55
|
+
sunset: '🌅 Purple to coral — warm and vibrant',
|
|
56
|
+
forest: '🌲 Natural greens — earthy and organic',
|
|
57
|
+
candy: '🍬 Sweet pastels — playful and fun',
|
|
58
|
+
minimal: '⬜ Black on white — pure simplicity',
|
|
59
|
+
midnight: '🌙 Deep purple-blue — elegant and modern',
|
|
60
|
+
retro: '📺 Orange on brown — nostalgic monospace',
|
|
61
|
+
glass: '🔮 Glassmorphism — blurred purple gradient',
|
|
62
|
+
aurora: '🌌 Northern lights — cyan meets purple',
|
|
63
|
+
};
|
|
64
|
+
for (const [name, desc] of Object.entries(descriptions)) {
|
|
65
|
+
console.log(` ${name.padEnd(12)} ${desc}`);
|
|
66
|
+
}
|
|
67
|
+
console.log(`
|
|
68
|
+
Usage: theme "${Object.keys(descriptions)[0]}"
|
|
69
|
+
`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getOutputPath(inputFile, customOutput) {
|
|
73
|
+
if (customOutput) return customOutput;
|
|
74
|
+
const base = path.basename(inputFile, '.clou');
|
|
75
|
+
return path.join(path.dirname(inputFile), base + '.html');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function openInBrowser(filePath) {
|
|
79
|
+
const absPath = path.resolve(filePath);
|
|
80
|
+
const { exec } = require('child_process');
|
|
81
|
+
|
|
82
|
+
if (process.platform === 'win32') {
|
|
83
|
+
exec(`start "" "${absPath}"`);
|
|
84
|
+
} else if (process.platform === 'darwin') {
|
|
85
|
+
exec(`open "${absPath}"`);
|
|
86
|
+
} else {
|
|
87
|
+
exec(`xdg-open "${absPath}"`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Detect if a .clou file is a terminal app (starts with "app" or has "print"/"ask" at top level)
|
|
92
|
+
function isTerminalApp(source) {
|
|
93
|
+
const trimmed = source.trim();
|
|
94
|
+
if (trimmed.startsWith('app ')) return true;
|
|
95
|
+
// Check if it uses terminal-only keywords at top level
|
|
96
|
+
const lines = trimmed.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('#'));
|
|
97
|
+
const terminalKeywords = ['print ', 'ask ', 'clear', 'run ', 'exit'];
|
|
98
|
+
for (const line of lines.slice(0, 10)) {
|
|
99
|
+
for (const kw of terminalKeywords) {
|
|
100
|
+
if (line.startsWith(kw)) return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function runTerminal(inputFile) {
|
|
107
|
+
const { tokenize } = require('../src/lexer');
|
|
108
|
+
const { parseTerminal } = require('../src/terminal-parser');
|
|
109
|
+
const { TerminalRuntime } = require('../src/terminal-runtime');
|
|
110
|
+
|
|
111
|
+
const source = fs.readFileSync(inputFile, 'utf-8');
|
|
112
|
+
const tokens = tokenize(source);
|
|
113
|
+
const ast = parseTerminal(tokens);
|
|
114
|
+
const runtime = new TerminalRuntime();
|
|
115
|
+
await runtime.run(ast);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function runFile(inputFile) {
|
|
119
|
+
const source = fs.readFileSync(inputFile, 'utf-8');
|
|
120
|
+
|
|
121
|
+
// Auto-detect: terminal app or website?
|
|
122
|
+
if (isTerminalApp(source)) {
|
|
123
|
+
runTerminal(inputFile).catch(err => {
|
|
124
|
+
console.error(`\n Clou Error: ${err.message}\n`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const basePath = path.dirname(path.resolve(inputFile));
|
|
131
|
+
const result = buildClou(source, { basePath });
|
|
132
|
+
|
|
133
|
+
if (result.pages) {
|
|
134
|
+
// Multi-page build
|
|
135
|
+
const outDir = path.dirname(path.resolve(inputFile));
|
|
136
|
+
for (const [filename, pageData] of Object.entries(result.pages)) {
|
|
137
|
+
const outPath = path.join(outDir, filename);
|
|
138
|
+
fs.writeFileSync(outPath, pageData.html, 'utf-8');
|
|
139
|
+
console.log(` Built: ${filename}`);
|
|
140
|
+
}
|
|
141
|
+
const mainFile = path.join(outDir, 'index.html');
|
|
142
|
+
console.log(' Opening in browser...');
|
|
143
|
+
openInBrowser(fs.existsSync(mainFile) ? mainFile : path.join(outDir, Object.keys(result.pages)[0]));
|
|
144
|
+
} else {
|
|
145
|
+
const outputFile = getOutputPath(inputFile);
|
|
146
|
+
fs.writeFileSync(outputFile, result.html, 'utf-8');
|
|
147
|
+
console.log(` Built: ${inputFile} -> ${outputFile}`);
|
|
148
|
+
console.log(' Opening in browser...');
|
|
149
|
+
openInBrowser(outputFile);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildFile(inputFile, outputFile) {
|
|
154
|
+
const source = fs.readFileSync(inputFile, 'utf-8');
|
|
155
|
+
const basePath = path.dirname(path.resolve(inputFile));
|
|
156
|
+
const result = buildClou(source, { basePath });
|
|
157
|
+
|
|
158
|
+
if (result.pages) {
|
|
159
|
+
const outDir = outputFile ? path.dirname(outputFile) : path.dirname(path.resolve(inputFile));
|
|
160
|
+
for (const [filename, pageData] of Object.entries(result.pages)) {
|
|
161
|
+
const outPath = path.join(outDir, filename);
|
|
162
|
+
fs.writeFileSync(outPath, pageData.html, 'utf-8');
|
|
163
|
+
console.log(` Built: ${filename}`);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
fs.writeFileSync(outputFile, result.html, 'utf-8');
|
|
167
|
+
console.log(` Built: ${inputFile} -> ${outputFile}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── Main ──────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
|
|
174
|
+
printHelp();
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (args[0] === 'themes' || args[0] === '--themes') {
|
|
179
|
+
printThemes();
|
|
180
|
+
process.exit(0);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (args[0] === 'ai') {
|
|
184
|
+
const aiPromptPath = path.resolve(__dirname, '..', 'ai', 'clou-ai-prompt.md');
|
|
185
|
+
const prompt = fs.readFileSync(aiPromptPath, 'utf-8');
|
|
186
|
+
|
|
187
|
+
// Try to copy to clipboard
|
|
188
|
+
try {
|
|
189
|
+
const { execSync } = require('child_process');
|
|
190
|
+
if (process.platform === 'win32') {
|
|
191
|
+
execSync('clip', { input: prompt });
|
|
192
|
+
} else if (process.platform === 'darwin') {
|
|
193
|
+
execSync('pbcopy', { input: prompt });
|
|
194
|
+
} else {
|
|
195
|
+
execSync('xclip -selection clipboard', { input: prompt });
|
|
196
|
+
}
|
|
197
|
+
console.log(`
|
|
198
|
+
╔═══════════════════════════════════════╗
|
|
199
|
+
║ CLOU AI Prompt ║
|
|
200
|
+
╚═══════════════════════════════════════╝
|
|
201
|
+
|
|
202
|
+
The Clou AI system prompt has been copied
|
|
203
|
+
to your clipboard!
|
|
204
|
+
|
|
205
|
+
Paste it into any AI (ChatGPT, Claude, etc.)
|
|
206
|
+
and the AI will become a Clou expert.
|
|
207
|
+
|
|
208
|
+
Then ask it things like:
|
|
209
|
+
"Build me a portfolio website"
|
|
210
|
+
"Create a landing page for a coffee shop"
|
|
211
|
+
"Make a quiz game for the terminal"
|
|
212
|
+
|
|
213
|
+
The AI will generate perfect Clou code!
|
|
214
|
+
`);
|
|
215
|
+
} catch (e) {
|
|
216
|
+
console.log(`
|
|
217
|
+
╔═══════════════════════════════════════╗
|
|
218
|
+
║ CLOU AI Prompt ║
|
|
219
|
+
╚═══════════════════════════════════════╝
|
|
220
|
+
|
|
221
|
+
AI prompt file location:
|
|
222
|
+
${aiPromptPath}
|
|
223
|
+
|
|
224
|
+
Copy the contents and paste into any AI
|
|
225
|
+
(ChatGPT, Claude, etc.) to teach it Clou!
|
|
226
|
+
`);
|
|
227
|
+
}
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (args[0] === 'playground' || args[0] === 'play') {
|
|
232
|
+
const playgroundPath = path.resolve(__dirname, '..', 'playground', 'index.html');
|
|
233
|
+
console.log(' Opening Clou Playground...');
|
|
234
|
+
openInBrowser(playgroundPath);
|
|
235
|
+
process.exit(0);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Smart detection: if first arg ends with .clou, treat as "clou run file.clou"
|
|
239
|
+
let command, inputFile;
|
|
240
|
+
|
|
241
|
+
if (args[0].endsWith('.clou')) {
|
|
242
|
+
command = 'run';
|
|
243
|
+
inputFile = args[0];
|
|
244
|
+
} else {
|
|
245
|
+
command = args[0];
|
|
246
|
+
inputFile = args[1];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!inputFile) {
|
|
250
|
+
console.error(' Error: No input file specified.');
|
|
251
|
+
console.error(' Usage: clou mysite.clou');
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!fs.existsSync(inputFile)) {
|
|
256
|
+
console.error(` Error: File not found: ${inputFile}`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
if (command === 'dev') {
|
|
262
|
+
const { DevServer } = require('../src/devserver');
|
|
263
|
+
const portIdx = args.indexOf('-p');
|
|
264
|
+
const port = portIdx !== -1 ? parseInt(args[portIdx + 1]) : 3000;
|
|
265
|
+
const server = new DevServer(inputFile, port);
|
|
266
|
+
server.start();
|
|
267
|
+
} else if (command === 'build') {
|
|
268
|
+
const outputIdx = args.indexOf('-o');
|
|
269
|
+
const outputFile = outputIdx !== -1 ? args[outputIdx + 1] : getOutputPath(inputFile);
|
|
270
|
+
buildFile(inputFile, outputFile);
|
|
271
|
+
} else if (command === 'run' || args[0].endsWith('.clou')) {
|
|
272
|
+
runFile(inputFile);
|
|
273
|
+
} else {
|
|
274
|
+
console.error(` Unknown command: ${command}`);
|
|
275
|
+
printHelp();
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.error(`\n Clou Error: ${err.message}\n`);
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|