aegis-framework 0.1.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 +239 -0
- package/aegis/__init__.py +19 -0
- package/aegis/__pycache__/__init__.cpython-312.pyc +0 -0
- package/aegis/builder/__init__.py +5 -0
- package/aegis/builder/__pycache__/__init__.cpython-312.pyc +0 -0
- package/aegis/builder/__pycache__/builder.cpython-312.pyc +0 -0
- package/aegis/builder/builder.py +301 -0
- package/aegis/cli/__init__.py +5 -0
- package/aegis/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/aegis/cli/__pycache__/cli.cpython-312.pyc +0 -0
- package/aegis/cli/cli.py +607 -0
- package/aegis/core/__init__.py +16 -0
- package/aegis/core/__pycache__/__init__.cpython-312.pyc +0 -0
- package/aegis/core/__pycache__/aegis.cpython-312.pyc +0 -0
- package/aegis/core/__pycache__/bridge.cpython-312.pyc +0 -0
- package/aegis/core/__pycache__/window.cpython-312.pyc +0 -0
- package/aegis/core/aegis.py +97 -0
- package/aegis/core/bridge.py +270 -0
- package/aegis/core/preload.py +160 -0
- package/aegis/core/window.py +603 -0
- package/aegis/runtime/__init__.py +1 -0
- package/aegis/runtime/aegis-api.js +519 -0
- package/aegis-cli.py +18 -0
- package/bin/aegis +81 -0
- package/package.json +51 -0
package/aegis/cli/cli.py
ADDED
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Aegis CLI - Command Line Interface for Aegis Framework
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
aegis init [name] Create a new Aegis project
|
|
7
|
+
aegis dev Run in development mode (hot-reload)
|
|
8
|
+
aegis run Run the project
|
|
9
|
+
aegis build Build AppImage
|
|
10
|
+
aegis --version Show version
|
|
11
|
+
aegis --help Show help
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import shutil
|
|
18
|
+
import json
|
|
19
|
+
import subprocess
|
|
20
|
+
import signal
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AegisCLI:
|
|
25
|
+
"""Aegis Command Line Interface"""
|
|
26
|
+
|
|
27
|
+
VERSION = "0.1.0"
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.parser = self._create_parser()
|
|
31
|
+
self.templates_dir = Path(__file__).parent.parent / 'templates'
|
|
32
|
+
|
|
33
|
+
def _create_parser(self):
|
|
34
|
+
"""Create argument parser"""
|
|
35
|
+
parser = argparse.ArgumentParser(
|
|
36
|
+
prog='aegis',
|
|
37
|
+
description='Aegis - Lightweight AppImage Framework',
|
|
38
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
39
|
+
epilog="""
|
|
40
|
+
Examples:
|
|
41
|
+
aegis init my-app Create a new project called 'my-app'
|
|
42
|
+
aegis dev Start development server with hot-reload
|
|
43
|
+
aegis build Package as AppImage
|
|
44
|
+
"""
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
'--version', '-v',
|
|
49
|
+
action='version',
|
|
50
|
+
version=f'Aegis v{self.VERSION}'
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
subparsers = parser.add_subparsers(dest='command', help='Commands')
|
|
54
|
+
|
|
55
|
+
# init command
|
|
56
|
+
init_parser = subparsers.add_parser('init', help='Create a new Aegis project')
|
|
57
|
+
init_parser.add_argument('name', nargs='?', default='.', help='Project name or directory')
|
|
58
|
+
init_parser.add_argument('--template', '-t', default='default', help='Project template')
|
|
59
|
+
|
|
60
|
+
# dev command
|
|
61
|
+
dev_parser = subparsers.add_parser('dev', help='Run in development mode')
|
|
62
|
+
dev_parser.add_argument('--port', '-p', type=int, default=8080, help='Dev server port')
|
|
63
|
+
dev_parser.add_argument('--no-reload', action='store_true', help='Disable hot-reload')
|
|
64
|
+
|
|
65
|
+
# run command
|
|
66
|
+
run_parser = subparsers.add_parser('run', help='Run the project')
|
|
67
|
+
run_parser.add_argument('--config', '-c', help='Config file path')
|
|
68
|
+
|
|
69
|
+
# build command
|
|
70
|
+
build_parser = subparsers.add_parser('build', help='Build AppImage')
|
|
71
|
+
build_parser.add_argument('--output', '-o', help='Output directory')
|
|
72
|
+
build_parser.add_argument('--name', '-n', help='AppImage name')
|
|
73
|
+
|
|
74
|
+
return parser
|
|
75
|
+
|
|
76
|
+
def run(self, args=None):
|
|
77
|
+
"""Run the CLI"""
|
|
78
|
+
parsed = self.parser.parse_args(args)
|
|
79
|
+
|
|
80
|
+
if parsed.command is None:
|
|
81
|
+
self.parser.print_help()
|
|
82
|
+
return 0
|
|
83
|
+
|
|
84
|
+
commands = {
|
|
85
|
+
'init': self.cmd_init,
|
|
86
|
+
'dev': self.cmd_dev,
|
|
87
|
+
'run': self.cmd_run,
|
|
88
|
+
'build': self.cmd_build
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
handler = commands.get(parsed.command)
|
|
92
|
+
if handler:
|
|
93
|
+
return handler(parsed)
|
|
94
|
+
|
|
95
|
+
return 1
|
|
96
|
+
|
|
97
|
+
def cmd_init(self, args):
|
|
98
|
+
"""Initialize a new Aegis project"""
|
|
99
|
+
project_name = args.name
|
|
100
|
+
|
|
101
|
+
# Determine project directory
|
|
102
|
+
if project_name == '.':
|
|
103
|
+
project_dir = Path.cwd()
|
|
104
|
+
project_name = project_dir.name
|
|
105
|
+
else:
|
|
106
|
+
project_dir = Path.cwd() / project_name
|
|
107
|
+
|
|
108
|
+
print(f"ā” Creating Aegis project: {project_name}")
|
|
109
|
+
|
|
110
|
+
# Check if directory exists and is not empty
|
|
111
|
+
if project_dir.exists() and any(project_dir.iterdir()):
|
|
112
|
+
print(f"ā ļø Directory '{project_dir}' is not empty.")
|
|
113
|
+
response = input("Continue anyway? [y/N] ")
|
|
114
|
+
if response.lower() != 'y':
|
|
115
|
+
return 1
|
|
116
|
+
|
|
117
|
+
# Create project directory
|
|
118
|
+
project_dir.mkdir(parents=True, exist_ok=True)
|
|
119
|
+
|
|
120
|
+
# Create project structure
|
|
121
|
+
self._create_project_files(project_dir, project_name)
|
|
122
|
+
|
|
123
|
+
print(f"""
|
|
124
|
+
ā
Project created successfully!
|
|
125
|
+
|
|
126
|
+
Next steps:
|
|
127
|
+
cd {project_name}
|
|
128
|
+
aegis dev
|
|
129
|
+
|
|
130
|
+
Happy coding! š
|
|
131
|
+
""")
|
|
132
|
+
|
|
133
|
+
return 0
|
|
134
|
+
|
|
135
|
+
def _create_project_files(self, project_dir, project_name):
|
|
136
|
+
"""Create all project files from templates"""
|
|
137
|
+
|
|
138
|
+
# Create subdirectories
|
|
139
|
+
(project_dir / 'src').mkdir(exist_ok=True)
|
|
140
|
+
(project_dir / 'assets').mkdir(exist_ok=True)
|
|
141
|
+
|
|
142
|
+
# Configuration file
|
|
143
|
+
config = {
|
|
144
|
+
'name': project_name,
|
|
145
|
+
'title': project_name.replace('-', ' ').title(),
|
|
146
|
+
'version': '1.0.0',
|
|
147
|
+
'main': 'src/index.html',
|
|
148
|
+
'preload': 'src/preload.js',
|
|
149
|
+
'width': 1200,
|
|
150
|
+
'height': 800,
|
|
151
|
+
'resizable': True,
|
|
152
|
+
'frame': True,
|
|
153
|
+
'devTools': True,
|
|
154
|
+
'contextMenu': True,
|
|
155
|
+
'icon': 'assets/icon.png',
|
|
156
|
+
'description': 'An Aegis application'
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
with open(project_dir / 'aegis.config.json', 'w') as f:
|
|
160
|
+
json.dump(config, f, indent=2)
|
|
161
|
+
|
|
162
|
+
# Main HTML
|
|
163
|
+
html_content = f'''<!DOCTYPE html>
|
|
164
|
+
<html lang="en">
|
|
165
|
+
<head>
|
|
166
|
+
<meta charset="UTF-8">
|
|
167
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
168
|
+
<title>{project_name}</title>
|
|
169
|
+
<link rel="stylesheet" href="styles.css">
|
|
170
|
+
</head>
|
|
171
|
+
<body>
|
|
172
|
+
<div class="app">
|
|
173
|
+
<header class="header">
|
|
174
|
+
<h1>ā” {project_name}</h1>
|
|
175
|
+
<p>Built with Aegis Framework</p>
|
|
176
|
+
</header>
|
|
177
|
+
|
|
178
|
+
<main class="main">
|
|
179
|
+
<div class="card">
|
|
180
|
+
<h2>Welcome to Aegis!</h2>
|
|
181
|
+
<p>Edit <code>src/index.html</code> to get started.</p>
|
|
182
|
+
|
|
183
|
+
<div class="demo">
|
|
184
|
+
<button id="btn-read" class="btn">š Read File</button>
|
|
185
|
+
<button id="btn-run" class="btn">ā” Run Command</button>
|
|
186
|
+
<button id="btn-dialog" class="btn btn-primary">š¬ Show Dialog</button>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<pre id="output" class="output">Output will appear here...</pre>
|
|
190
|
+
</div>
|
|
191
|
+
</main>
|
|
192
|
+
|
|
193
|
+
<footer class="footer">
|
|
194
|
+
Powered by Aegis v0.1.0 | WebKit2GTK + Python
|
|
195
|
+
</footer>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<script src="app.js"></script>
|
|
199
|
+
</body>
|
|
200
|
+
</html>
|
|
201
|
+
'''
|
|
202
|
+
with open(project_dir / 'src' / 'index.html', 'w') as f:
|
|
203
|
+
f.write(html_content)
|
|
204
|
+
|
|
205
|
+
# Styles
|
|
206
|
+
css_content = '''/* Aegis App Styles */
|
|
207
|
+
:root {
|
|
208
|
+
--primary: #00ff88;
|
|
209
|
+
--primary-dark: #00cc6a;
|
|
210
|
+
--bg: #0a0a0f;
|
|
211
|
+
--bg-card: #12121a;
|
|
212
|
+
--text: #ffffff;
|
|
213
|
+
--text-muted: #888899;
|
|
214
|
+
--border: #2a2a3a;
|
|
215
|
+
--radius: 12px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
* {
|
|
219
|
+
margin: 0;
|
|
220
|
+
padding: 0;
|
|
221
|
+
box-sizing: border-box;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
body {
|
|
225
|
+
font-family: 'Segoe UI', system-ui, sans-serif;
|
|
226
|
+
background: var(--bg);
|
|
227
|
+
color: var(--text);
|
|
228
|
+
min-height: 100vh;
|
|
229
|
+
display: flex;
|
|
230
|
+
flex-direction: column;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.app {
|
|
234
|
+
display: flex;
|
|
235
|
+
flex-direction: column;
|
|
236
|
+
min-height: 100vh;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.header {
|
|
240
|
+
text-align: center;
|
|
241
|
+
padding: 3rem 2rem;
|
|
242
|
+
background: linear-gradient(180deg, #1a1a2a 0%, var(--bg) 100%);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.header h1 {
|
|
246
|
+
font-size: 2.5rem;
|
|
247
|
+
margin-bottom: 0.5rem;
|
|
248
|
+
background: linear-gradient(135deg, var(--primary), #00aaff);
|
|
249
|
+
-webkit-background-clip: text;
|
|
250
|
+
-webkit-text-fill-color: transparent;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.header p {
|
|
254
|
+
color: var(--text-muted);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.main {
|
|
258
|
+
flex: 1;
|
|
259
|
+
display: flex;
|
|
260
|
+
align-items: center;
|
|
261
|
+
justify-content: center;
|
|
262
|
+
padding: 2rem;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.card {
|
|
266
|
+
background: var(--bg-card);
|
|
267
|
+
border: 1px solid var(--border);
|
|
268
|
+
border-radius: var(--radius);
|
|
269
|
+
padding: 2rem;
|
|
270
|
+
max-width: 600px;
|
|
271
|
+
width: 100%;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.card h2 {
|
|
275
|
+
margin-bottom: 1rem;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.card p {
|
|
279
|
+
color: var(--text-muted);
|
|
280
|
+
margin-bottom: 1.5rem;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.card code {
|
|
284
|
+
background: #2a2a3a;
|
|
285
|
+
padding: 0.2rem 0.5rem;
|
|
286
|
+
border-radius: 4px;
|
|
287
|
+
font-family: 'Fira Code', monospace;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.demo {
|
|
291
|
+
display: flex;
|
|
292
|
+
gap: 1rem;
|
|
293
|
+
margin-bottom: 1.5rem;
|
|
294
|
+
flex-wrap: wrap;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.btn {
|
|
298
|
+
padding: 0.75rem 1.5rem;
|
|
299
|
+
border: 1px solid var(--border);
|
|
300
|
+
border-radius: 8px;
|
|
301
|
+
background: var(--bg);
|
|
302
|
+
color: var(--text);
|
|
303
|
+
cursor: pointer;
|
|
304
|
+
font-size: 1rem;
|
|
305
|
+
transition: all 0.2s;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.btn:hover {
|
|
309
|
+
background: #1a1a2a;
|
|
310
|
+
border-color: var(--primary);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.btn-primary {
|
|
314
|
+
background: var(--primary);
|
|
315
|
+
color: #000;
|
|
316
|
+
border-color: var(--primary);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.btn-primary:hover {
|
|
320
|
+
background: var(--primary-dark);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.output {
|
|
324
|
+
background: #000;
|
|
325
|
+
border: 1px solid var(--border);
|
|
326
|
+
border-radius: 8px;
|
|
327
|
+
padding: 1rem;
|
|
328
|
+
font-family: 'Fira Code', monospace;
|
|
329
|
+
font-size: 0.9rem;
|
|
330
|
+
color: var(--primary);
|
|
331
|
+
overflow-x: auto;
|
|
332
|
+
white-space: pre-wrap;
|
|
333
|
+
word-break: break-all;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.footer {
|
|
337
|
+
text-align: center;
|
|
338
|
+
padding: 1.5rem;
|
|
339
|
+
color: var(--text-muted);
|
|
340
|
+
font-size: 0.9rem;
|
|
341
|
+
border-top: 1px solid var(--border);
|
|
342
|
+
}
|
|
343
|
+
'''
|
|
344
|
+
with open(project_dir / 'src' / 'styles.css', 'w') as f:
|
|
345
|
+
f.write(css_content)
|
|
346
|
+
|
|
347
|
+
# JavaScript
|
|
348
|
+
js_content = '''/**
|
|
349
|
+
* Aegis App - Main JavaScript
|
|
350
|
+
*/
|
|
351
|
+
|
|
352
|
+
// Wait for Aegis to be ready
|
|
353
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
354
|
+
const output = document.getElementById('output');
|
|
355
|
+
|
|
356
|
+
// Check if running in Aegis
|
|
357
|
+
if (!Aegis.isAegis()) {
|
|
358
|
+
output.textContent = 'Not running in Aegis environment.\\nRun with: aegis dev';
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
output.textContent = 'ā
Aegis is ready!\\n\\nClick a button to test the API.';
|
|
363
|
+
|
|
364
|
+
// Read file button
|
|
365
|
+
document.getElementById('btn-read').addEventListener('click', async () => {
|
|
366
|
+
try {
|
|
367
|
+
const result = await Aegis.read({ path: '.' });
|
|
368
|
+
output.textContent = 'Directory contents:\\n\\n' +
|
|
369
|
+
result.entries.map(e => `${e.isDirectory ? 'š' : 'š'} ${e.name}`).join('\\n');
|
|
370
|
+
} catch (err) {
|
|
371
|
+
output.textContent = 'Error: ' + err.message;
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Run command button
|
|
376
|
+
document.getElementById('btn-run').addEventListener('click', async () => {
|
|
377
|
+
try {
|
|
378
|
+
const result = await Aegis.run({ sh: 'uname -a' });
|
|
379
|
+
output.textContent = 'System info:\\n\\n' + result.output;
|
|
380
|
+
} catch (err) {
|
|
381
|
+
output.textContent = 'Error: ' + err.message;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Dialog button
|
|
386
|
+
document.getElementById('btn-dialog').addEventListener('click', async () => {
|
|
387
|
+
try {
|
|
388
|
+
const result = await Aegis.dialog.message({
|
|
389
|
+
type: 'info',
|
|
390
|
+
title: 'Hello from Aegis!',
|
|
391
|
+
message: 'This is a native GTK dialog.\\nPretty cool, right?'
|
|
392
|
+
});
|
|
393
|
+
output.textContent = 'Dialog closed! Response: ' + JSON.stringify(result);
|
|
394
|
+
} catch (err) {
|
|
395
|
+
output.textContent = 'Error: ' + err.message;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
'''
|
|
400
|
+
with open(project_dir / 'src' / 'app.js', 'w') as f:
|
|
401
|
+
f.write(js_content)
|
|
402
|
+
|
|
403
|
+
# Preload
|
|
404
|
+
preload_content = '''/**
|
|
405
|
+
* Aegis Preload Configuration
|
|
406
|
+
*
|
|
407
|
+
* This file controls which Aegis APIs are exposed to your frontend.
|
|
408
|
+
* For security, only expose the APIs you actually need.
|
|
409
|
+
*/
|
|
410
|
+
|
|
411
|
+
// Expose specific APIs
|
|
412
|
+
Aegis.expose([
|
|
413
|
+
'read', // File reading
|
|
414
|
+
'write', // File writing
|
|
415
|
+
'run', // Command execution
|
|
416
|
+
'dialog', // Native dialogs
|
|
417
|
+
'app', // App control
|
|
418
|
+
'exists', // File existence check
|
|
419
|
+
'mkdir', // Create directories
|
|
420
|
+
'env' // Environment variables
|
|
421
|
+
]);
|
|
422
|
+
|
|
423
|
+
// Configure Aegis
|
|
424
|
+
Aegis.config({
|
|
425
|
+
allowRemoteContent: false,
|
|
426
|
+
enableDevTools: true
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
console.log('ā
Preload configured');
|
|
430
|
+
'''
|
|
431
|
+
with open(project_dir / 'src' / 'preload.js', 'w') as f:
|
|
432
|
+
f.write(preload_content)
|
|
433
|
+
|
|
434
|
+
# README
|
|
435
|
+
readme_content = f'''# {project_name}
|
|
436
|
+
|
|
437
|
+
An application built with [Aegis Framework](https://github.com/your-repo/aegis).
|
|
438
|
+
|
|
439
|
+
## Getting Started
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
# Development mode
|
|
443
|
+
aegis dev
|
|
444
|
+
|
|
445
|
+
# Build AppImage
|
|
446
|
+
aegis build
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Project Structure
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
{project_name}/
|
|
453
|
+
āāā aegis.config.json # Project configuration
|
|
454
|
+
āāā src/
|
|
455
|
+
ā āāā index.html # Main HTML
|
|
456
|
+
ā āāā styles.css # Styles
|
|
457
|
+
ā āāā app.js # JavaScript
|
|
458
|
+
ā āāā preload.js # Security configuration
|
|
459
|
+
āāā assets/
|
|
460
|
+
āāā icon.png # App icon
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Aegis API
|
|
464
|
+
|
|
465
|
+
```javascript
|
|
466
|
+
// Read files
|
|
467
|
+
const content = await Aegis.read({{ path: '.', file: 'data.txt' }});
|
|
468
|
+
|
|
469
|
+
// Write files
|
|
470
|
+
await Aegis.write({{ path: '.', file: 'output.txt', content: 'Hello!' }});
|
|
471
|
+
|
|
472
|
+
// Run commands
|
|
473
|
+
const result = await Aegis.run({{ sh: 'ls -la' }});
|
|
474
|
+
|
|
475
|
+
// Dialogs
|
|
476
|
+
await Aegis.dialog.message({{ type: 'info', title: 'Hello', message: 'World!' }});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## License
|
|
480
|
+
|
|
481
|
+
MIT
|
|
482
|
+
'''
|
|
483
|
+
with open(project_dir / 'README.md', 'w') as f:
|
|
484
|
+
f.write(readme_content)
|
|
485
|
+
|
|
486
|
+
# .gitignore
|
|
487
|
+
gitignore_content = '''# Aegis
|
|
488
|
+
dist/
|
|
489
|
+
*.AppImage
|
|
490
|
+
*.AppDir/
|
|
491
|
+
|
|
492
|
+
# Python
|
|
493
|
+
__pycache__/
|
|
494
|
+
*.pyc
|
|
495
|
+
.venv/
|
|
496
|
+
|
|
497
|
+
# Node (if using npm for frontend)
|
|
498
|
+
node_modules/
|
|
499
|
+
|
|
500
|
+
# IDE
|
|
501
|
+
.vscode/
|
|
502
|
+
.idea/
|
|
503
|
+
'''
|
|
504
|
+
with open(project_dir / '.gitignore', 'w') as f:
|
|
505
|
+
f.write(gitignore_content)
|
|
506
|
+
|
|
507
|
+
print(f" š Created project structure")
|
|
508
|
+
print(f" š aegis.config.json")
|
|
509
|
+
print(f" š src/index.html")
|
|
510
|
+
print(f" š src/styles.css")
|
|
511
|
+
print(f" š src/app.js")
|
|
512
|
+
print(f" š src/preload.js")
|
|
513
|
+
print(f" š README.md")
|
|
514
|
+
|
|
515
|
+
def cmd_dev(self, args):
|
|
516
|
+
"""Run in development mode"""
|
|
517
|
+
print("ā” Starting Aegis in development mode...")
|
|
518
|
+
|
|
519
|
+
# Check for config
|
|
520
|
+
if not Path('aegis.config.json').exists():
|
|
521
|
+
print("ā No aegis.config.json found. Run 'aegis init' first.")
|
|
522
|
+
return 1
|
|
523
|
+
|
|
524
|
+
# Import and run
|
|
525
|
+
try:
|
|
526
|
+
from aegis.core.aegis import AegisApp
|
|
527
|
+
app = AegisApp()
|
|
528
|
+
|
|
529
|
+
# Enable dev tools
|
|
530
|
+
app.config['devTools'] = True
|
|
531
|
+
|
|
532
|
+
print(f"š Loading: {app.config.get('main', 'index.html')}")
|
|
533
|
+
print("š Hot-reload: Enabled (save files to refresh)")
|
|
534
|
+
print("š ļø DevTools: Right-click ā Inspect Element")
|
|
535
|
+
print("")
|
|
536
|
+
|
|
537
|
+
app.run()
|
|
538
|
+
|
|
539
|
+
except ImportError as e:
|
|
540
|
+
print(f"ā Missing dependency: {e}")
|
|
541
|
+
print("Make sure you have installed: python3-gi gir1.2-webkit2-4.1")
|
|
542
|
+
return 1
|
|
543
|
+
except Exception as e:
|
|
544
|
+
print(f"ā Error: {e}")
|
|
545
|
+
return 1
|
|
546
|
+
|
|
547
|
+
return 0
|
|
548
|
+
|
|
549
|
+
def cmd_run(self, args):
|
|
550
|
+
"""Run the project (production mode)"""
|
|
551
|
+
print("ā” Running Aegis application...")
|
|
552
|
+
|
|
553
|
+
config_path = args.config or 'aegis.config.json'
|
|
554
|
+
|
|
555
|
+
if not Path(config_path).exists():
|
|
556
|
+
print(f"ā Config not found: {config_path}")
|
|
557
|
+
return 1
|
|
558
|
+
|
|
559
|
+
try:
|
|
560
|
+
from aegis.core.aegis import AegisApp
|
|
561
|
+
app = AegisApp(config_path)
|
|
562
|
+
app.config['devTools'] = False
|
|
563
|
+
app.run()
|
|
564
|
+
|
|
565
|
+
except Exception as e:
|
|
566
|
+
print(f"ā Error: {e}")
|
|
567
|
+
return 1
|
|
568
|
+
|
|
569
|
+
return 0
|
|
570
|
+
|
|
571
|
+
def cmd_build(self, args):
|
|
572
|
+
"""Build AppImage"""
|
|
573
|
+
print("š¦ Building AppImage...")
|
|
574
|
+
|
|
575
|
+
if not Path('aegis.config.json').exists():
|
|
576
|
+
print("ā No aegis.config.json found.")
|
|
577
|
+
return 1
|
|
578
|
+
|
|
579
|
+
try:
|
|
580
|
+
from aegis.builder.builder import AegisBuilder
|
|
581
|
+
|
|
582
|
+
builder = AegisBuilder()
|
|
583
|
+
output = args.output or 'dist'
|
|
584
|
+
name = args.name
|
|
585
|
+
|
|
586
|
+
appimage_path = builder.build(output_dir=output, name=name)
|
|
587
|
+
|
|
588
|
+
print(f"\nā
AppImage created: {appimage_path}")
|
|
589
|
+
print(f" Size: {Path(appimage_path).stat().st_size / 1024 / 1024:.1f} MB")
|
|
590
|
+
|
|
591
|
+
except Exception as e:
|
|
592
|
+
print(f"ā Build failed: {e}")
|
|
593
|
+
import traceback
|
|
594
|
+
traceback.print_exc()
|
|
595
|
+
return 1
|
|
596
|
+
|
|
597
|
+
return 0
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def main():
|
|
601
|
+
"""Entry point for CLI"""
|
|
602
|
+
cli = AegisCLI()
|
|
603
|
+
sys.exit(cli.run())
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
if __name__ == '__main__':
|
|
607
|
+
main()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Aegis Core Module
|
|
3
|
+
Contains window management and IPC bridge
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Lazy imports to allow CLI to work without GTK
|
|
7
|
+
def __getattr__(name):
|
|
8
|
+
if name == 'AegisApp':
|
|
9
|
+
from aegis.core.aegis import AegisApp
|
|
10
|
+
return AegisApp
|
|
11
|
+
elif name == 'AegisWindow':
|
|
12
|
+
from aegis.core.window import AegisWindow
|
|
13
|
+
return AegisWindow
|
|
14
|
+
raise AttributeError(f"module 'aegis.core' has no attribute '{name}'")
|
|
15
|
+
|
|
16
|
+
__all__ = ['AegisApp', 'AegisWindow']
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|