magmascript 3.2.0__tar.gz → 3.2.2__tar.gz
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.
- {magmascript-3.2.0 → magmascript-3.2.2}/PKG-INFO +53 -25
- {magmascript-3.2.0 → magmascript-3.2.2}/README.md +48 -22
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/__init__.py +1 -1
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/cli.py +248 -138
- magmascript-3.2.2/magmascript/codegen/__init__.py +23 -0
- magmascript-3.2.2/magmascript/codegen/c.py +284 -0
- magmascript-3.2.2/magmascript/core/command_registry.py +55 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/github.py +1 -1
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mc1/client.py +22 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mcp/client.py +3 -3
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/hypnagogia.py +92 -67
- magmascript-3.2.2/magmascript/lang/pretty.py +262 -0
- magmascript-3.2.2/magmascript/lang/visitor.py +100 -0
- magmascript-3.2.2/magmascript/scaffold/__init__.py +70 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/PKG-INFO +53 -25
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/SOURCES.txt +6 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/pyproject.toml +5 -3
- {magmascript-3.2.0 → magmascript-3.2.2}/LICENSE +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/cache.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/commands.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/config.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/exceptions.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/output.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/registry.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/rpc.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/core/runner.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/archive/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/archive/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/gh/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/gh/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/gh/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/lastfm/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/lastfm/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mac/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mac/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mac/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mb/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mb/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mc1/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mc1/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mcp/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/mcp/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/archive.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/met_museum.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/openverse.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/pexels.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/pixabay.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/providers/smithsonian.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/media/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/pi/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/pi/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/pi/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/rights/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/rights/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/rights/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/scores/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/scores/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/scores/tools.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/search/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/domains/search/client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/ast_nodes.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/astheno/__init__.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/astheno/arena.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/astheno/dump.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/astheno/floorplan.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/astheno/numeric.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/builtins.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/domain_bridge.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/environment.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/interpreter.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/lexer.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/parser.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/pygments_mgs.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/tokens.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/lang/util.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript/repl.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/dependency_links.txt +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/entry_points.txt +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/requires.txt +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/magmascript.egg-info/top_level.txt +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/setup.cfg +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_astheno.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_cache.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_classes.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_cli.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_commands.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_domain_bridge.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_import.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_lang.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_mac.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_mc1.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_mcp_client.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_rpc.py +0 -0
- {magmascript-3.2.0 → magmascript-3.2.2}/tests/test_try_catch.py +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: magmascript
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.2
|
|
4
4
|
Summary: Scripting toolkit with domain-first subcommands
|
|
5
5
|
Author: Jake McCoy
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://
|
|
8
|
-
Project-URL:
|
|
7
|
+
Project-URL: Homepage, https://magmacrunch.com/ware/magmascript/
|
|
8
|
+
Project-URL: Documentation, https://github.com/magmacrunch-media/magmascript/wiki
|
|
9
|
+
Project-URL: Repository, https://github.com/magmacrunch-media/magmascript
|
|
10
|
+
Project-URL: Changelog, https://github.com/magmacrunch-media/magmascript/blob/main/CHANGELOG.md
|
|
9
11
|
Keywords: mcp,scripting,cli,magmacrunch
|
|
10
12
|
Classifier: Development Status :: 3 - Alpha
|
|
11
13
|
Classifier: Environment :: Console
|
|
@@ -39,8 +41,30 @@ Scripting toolkit with domain-first subcommands for managing magmacrunch.com inf
|
|
|
39
41
|
|
|
40
42
|
## Install
|
|
41
43
|
|
|
44
|
+
Requires Python >= 3.11.
|
|
45
|
+
|
|
46
|
+
### pip (recommended)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install magmascript
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### pipx (best for CLI-only usage)
|
|
53
|
+
|
|
42
54
|
```bash
|
|
43
|
-
|
|
55
|
+
pipx install magmascript
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Homebrew (macOS / Linux)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
brew install magmacrunch-media/tap/magmascript
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Development
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/magmacrunch-media/magmascript.git
|
|
44
68
|
cd magmascript
|
|
45
69
|
python3 -m venv .venv
|
|
46
70
|
.venv/bin/pip install -e ".[all]"
|
|
@@ -71,7 +95,7 @@ user = "jake"
|
|
|
71
95
|
|
|
72
96
|
[gh]
|
|
73
97
|
token = "ghp_..."
|
|
74
|
-
owner = "
|
|
98
|
+
owner = "magmacrunch-media"
|
|
75
99
|
repo = "magmacrunch.com"
|
|
76
100
|
|
|
77
101
|
[project]
|
|
@@ -396,7 +420,7 @@ this ground was scorched at line 3 (garrisoned at line 1)
|
|
|
396
420
|
|
|
397
421
|
`floorplan` is the only new reserved word; everything else is a shadowable
|
|
398
422
|
builtin, so existing scripts are unaffected. Full reference on the
|
|
399
|
-
[Asthenosphere wiki page](https://github.com/
|
|
423
|
+
[Asthenosphere wiki page](https://github.com/magmacrunch-media/magmascript/wiki/Asthenosphere).
|
|
400
424
|
|
|
401
425
|
### REPL
|
|
402
426
|
|
|
@@ -468,6 +492,10 @@ Also on the CLI: `magmascript mc1 status`, `mc1 info`, `mc1 processes`,
|
|
|
468
492
|
`mc1 restart <service>`, `mc1 power`, `mc1 set-power-mode <always-on|sleep>`,
|
|
469
493
|
`mc1 wake <mac>`, `mc1 reboot`.
|
|
470
494
|
|
|
495
|
+
> **Note:** MC1 commands connect over SSH. Don't run them on MC1 itself — they
|
|
496
|
+
> will try to SSH into the configured host, which on MC1 means connecting to
|
|
497
|
+
> itself and hanging. Use these from your Mac, Pi, or any other machine.
|
|
498
|
+
|
|
471
499
|
### Mac Domain — Mac management (via SSH)
|
|
472
500
|
```magmascript
|
|
473
501
|
// In a .mgs script, or: magmascript mac info
|
|
@@ -600,7 +628,7 @@ first use, not at startup, so a domain may hold real resources. Built-in domains
|
|
|
600
628
|
win a name clash, and an entry point that fails to import is skipped rather than
|
|
601
629
|
breaking the interpreter.
|
|
602
630
|
|
|
603
|
-
[texastoast](https://github.com/
|
|
631
|
+
[texastoast](https://github.com/magmacrunch-media/texastoast) is the first:
|
|
604
632
|
`pip install texastoast` and `.mgs` scripts can drive a game engine. It
|
|
605
633
|
registers under two names, `texastoast` and the shorter `tt`.
|
|
606
634
|
|
|
@@ -649,24 +677,24 @@ gh_workflows # GitHub commands
|
|
|
649
677
|
|
|
650
678
|
## Documentation
|
|
651
679
|
|
|
652
|
-
Full documentation on the [Wiki](https://github.com/
|
|
653
|
-
- [MagmaScript Language](https://github.com/
|
|
654
|
-
- [Configuration](https://github.com/
|
|
655
|
-
- [MCP Domain](https://github.com/
|
|
656
|
-
- [Pi Domain](https://github.com/
|
|
657
|
-
- [MC1 Domain](https://github.com/
|
|
658
|
-
- [Mac Domain](https://github.com/
|
|
659
|
-
- [GitHub Domain](https://github.com/
|
|
660
|
-
- [Scores Domain](https://github.com/
|
|
661
|
-
- [Rights Domain](https://github.com/
|
|
662
|
-
- [Archive Domain](https://github.com/
|
|
663
|
-
- [Last.fm Domain](https://github.com/
|
|
664
|
-
- [MusicBrainz Domain](https://github.com/
|
|
665
|
-
- [Search Domain](https://github.com/
|
|
666
|
-
- [Media Domain](https://github.com/
|
|
667
|
-
- [Example Scripts](https://github.com/
|
|
668
|
-
- [Asthenosphere](https://github.com/
|
|
669
|
-
- [Architecture](https://github.com/
|
|
680
|
+
Full documentation on the [Wiki](https://github.com/magmacrunch-media/magmascript/wiki):
|
|
681
|
+
- [MagmaScript Language](https://github.com/magmacrunch-media/magmascript/wiki/MagmaScript-Language)
|
|
682
|
+
- [Configuration](https://github.com/magmacrunch-media/magmascript/wiki/Configuration)
|
|
683
|
+
- [MCP Domain](https://github.com/magmacrunch-media/magmascript/wiki/MCP-Domain)
|
|
684
|
+
- [Pi Domain](https://github.com/magmacrunch-media/magmascript/wiki/Pi-Domain)
|
|
685
|
+
- [MC1 Domain](https://github.com/magmacrunch-media/magmascript/wiki/MC1-Domain)
|
|
686
|
+
- [Mac Domain](https://github.com/magmacrunch-media/magmascript/wiki/Mac-Domain)
|
|
687
|
+
- [GitHub Domain](https://github.com/magmacrunch-media/magmascript/wiki/GitHub-Domain)
|
|
688
|
+
- [Scores Domain](https://github.com/magmacrunch-media/magmascript/wiki/Scores-Domain)
|
|
689
|
+
- [Rights Domain](https://github.com/magmacrunch-media/magmascript/wiki/Rights-Domain)
|
|
690
|
+
- [Archive Domain](https://github.com/magmacrunch-media/magmascript/wiki/Archive-Domain)
|
|
691
|
+
- [Last.fm Domain](https://github.com/magmacrunch-media/magmascript/wiki/Last.fm-Domain)
|
|
692
|
+
- [MusicBrainz Domain](https://github.com/magmacrunch-media/magmascript/wiki/MusicBrainz-Domain)
|
|
693
|
+
- [Search Domain](https://github.com/magmacrunch-media/magmascript/wiki/Search-Domain)
|
|
694
|
+
- [Media Domain](https://github.com/magmacrunch-media/magmascript/wiki/Media-Domain)
|
|
695
|
+
- [Example Scripts](https://github.com/magmacrunch-media/magmascript/wiki/Example-Scripts)
|
|
696
|
+
- [Asthenosphere](https://github.com/magmacrunch-media/magmascript/wiki/Asthenosphere)
|
|
697
|
+
- [Architecture](https://github.com/magmacrunch-media/magmascript/wiki/Architecture)
|
|
670
698
|
|
|
671
699
|
## License
|
|
672
700
|
|
|
@@ -4,8 +4,30 @@ Scripting toolkit with domain-first subcommands for managing magmacrunch.com inf
|
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
+
Requires Python >= 3.11.
|
|
8
|
+
|
|
9
|
+
### pip (recommended)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install magmascript
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### pipx (best for CLI-only usage)
|
|
16
|
+
|
|
7
17
|
```bash
|
|
8
|
-
|
|
18
|
+
pipx install magmascript
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Homebrew (macOS / Linux)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
brew install magmacrunch-media/tap/magmascript
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Development
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/magmacrunch-media/magmascript.git
|
|
9
31
|
cd magmascript
|
|
10
32
|
python3 -m venv .venv
|
|
11
33
|
.venv/bin/pip install -e ".[all]"
|
|
@@ -36,7 +58,7 @@ user = "jake"
|
|
|
36
58
|
|
|
37
59
|
[gh]
|
|
38
60
|
token = "ghp_..."
|
|
39
|
-
owner = "
|
|
61
|
+
owner = "magmacrunch-media"
|
|
40
62
|
repo = "magmacrunch.com"
|
|
41
63
|
|
|
42
64
|
[project]
|
|
@@ -361,7 +383,7 @@ this ground was scorched at line 3 (garrisoned at line 1)
|
|
|
361
383
|
|
|
362
384
|
`floorplan` is the only new reserved word; everything else is a shadowable
|
|
363
385
|
builtin, so existing scripts are unaffected. Full reference on the
|
|
364
|
-
[Asthenosphere wiki page](https://github.com/
|
|
386
|
+
[Asthenosphere wiki page](https://github.com/magmacrunch-media/magmascript/wiki/Asthenosphere).
|
|
365
387
|
|
|
366
388
|
### REPL
|
|
367
389
|
|
|
@@ -433,6 +455,10 @@ Also on the CLI: `magmascript mc1 status`, `mc1 info`, `mc1 processes`,
|
|
|
433
455
|
`mc1 restart <service>`, `mc1 power`, `mc1 set-power-mode <always-on|sleep>`,
|
|
434
456
|
`mc1 wake <mac>`, `mc1 reboot`.
|
|
435
457
|
|
|
458
|
+
> **Note:** MC1 commands connect over SSH. Don't run them on MC1 itself — they
|
|
459
|
+
> will try to SSH into the configured host, which on MC1 means connecting to
|
|
460
|
+
> itself and hanging. Use these from your Mac, Pi, or any other machine.
|
|
461
|
+
|
|
436
462
|
### Mac Domain — Mac management (via SSH)
|
|
437
463
|
```magmascript
|
|
438
464
|
// In a .mgs script, or: magmascript mac info
|
|
@@ -565,7 +591,7 @@ first use, not at startup, so a domain may hold real resources. Built-in domains
|
|
|
565
591
|
win a name clash, and an entry point that fails to import is skipped rather than
|
|
566
592
|
breaking the interpreter.
|
|
567
593
|
|
|
568
|
-
[texastoast](https://github.com/
|
|
594
|
+
[texastoast](https://github.com/magmacrunch-media/texastoast) is the first:
|
|
569
595
|
`pip install texastoast` and `.mgs` scripts can drive a game engine. It
|
|
570
596
|
registers under two names, `texastoast` and the shorter `tt`.
|
|
571
597
|
|
|
@@ -614,24 +640,24 @@ gh_workflows # GitHub commands
|
|
|
614
640
|
|
|
615
641
|
## Documentation
|
|
616
642
|
|
|
617
|
-
Full documentation on the [Wiki](https://github.com/
|
|
618
|
-
- [MagmaScript Language](https://github.com/
|
|
619
|
-
- [Configuration](https://github.com/
|
|
620
|
-
- [MCP Domain](https://github.com/
|
|
621
|
-
- [Pi Domain](https://github.com/
|
|
622
|
-
- [MC1 Domain](https://github.com/
|
|
623
|
-
- [Mac Domain](https://github.com/
|
|
624
|
-
- [GitHub Domain](https://github.com/
|
|
625
|
-
- [Scores Domain](https://github.com/
|
|
626
|
-
- [Rights Domain](https://github.com/
|
|
627
|
-
- [Archive Domain](https://github.com/
|
|
628
|
-
- [Last.fm Domain](https://github.com/
|
|
629
|
-
- [MusicBrainz Domain](https://github.com/
|
|
630
|
-
- [Search Domain](https://github.com/
|
|
631
|
-
- [Media Domain](https://github.com/
|
|
632
|
-
- [Example Scripts](https://github.com/
|
|
633
|
-
- [Asthenosphere](https://github.com/
|
|
634
|
-
- [Architecture](https://github.com/
|
|
643
|
+
Full documentation on the [Wiki](https://github.com/magmacrunch-media/magmascript/wiki):
|
|
644
|
+
- [MagmaScript Language](https://github.com/magmacrunch-media/magmascript/wiki/MagmaScript-Language)
|
|
645
|
+
- [Configuration](https://github.com/magmacrunch-media/magmascript/wiki/Configuration)
|
|
646
|
+
- [MCP Domain](https://github.com/magmacrunch-media/magmascript/wiki/MCP-Domain)
|
|
647
|
+
- [Pi Domain](https://github.com/magmacrunch-media/magmascript/wiki/Pi-Domain)
|
|
648
|
+
- [MC1 Domain](https://github.com/magmacrunch-media/magmascript/wiki/MC1-Domain)
|
|
649
|
+
- [Mac Domain](https://github.com/magmacrunch-media/magmascript/wiki/Mac-Domain)
|
|
650
|
+
- [GitHub Domain](https://github.com/magmacrunch-media/magmascript/wiki/GitHub-Domain)
|
|
651
|
+
- [Scores Domain](https://github.com/magmacrunch-media/magmascript/wiki/Scores-Domain)
|
|
652
|
+
- [Rights Domain](https://github.com/magmacrunch-media/magmascript/wiki/Rights-Domain)
|
|
653
|
+
- [Archive Domain](https://github.com/magmacrunch-media/magmascript/wiki/Archive-Domain)
|
|
654
|
+
- [Last.fm Domain](https://github.com/magmacrunch-media/magmascript/wiki/Last.fm-Domain)
|
|
655
|
+
- [MusicBrainz Domain](https://github.com/magmacrunch-media/magmascript/wiki/MusicBrainz-Domain)
|
|
656
|
+
- [Search Domain](https://github.com/magmacrunch-media/magmascript/wiki/Search-Domain)
|
|
657
|
+
- [Media Domain](https://github.com/magmacrunch-media/magmascript/wiki/Media-Domain)
|
|
658
|
+
- [Example Scripts](https://github.com/magmacrunch-media/magmascript/wiki/Example-Scripts)
|
|
659
|
+
- [Asthenosphere](https://github.com/magmacrunch-media/magmascript/wiki/Asthenosphere)
|
|
660
|
+
- [Architecture](https://github.com/magmacrunch-media/magmascript/wiki/Architecture)
|
|
635
661
|
|
|
636
662
|
## License
|
|
637
663
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""magmascript — a scripting toolkit with domain-first subcommands."""
|
|
2
2
|
|
|
3
|
-
__version__ = "3.2.
|
|
3
|
+
__version__ = "3.2.2"
|
|
4
4
|
|
|
5
5
|
from magmascript.core.config import Config, GHConfig, MediaConfig, MC1Config, PIConfig, get_config, load_config, set_config
|
|
6
6
|
from magmascript.core.registry import get_domain, list_domains, register_domain
|
|
@@ -11,12 +11,46 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import sys
|
|
14
|
+
from functools import wraps
|
|
15
|
+
from typing import Callable
|
|
14
16
|
|
|
15
17
|
from magmascript.core.config import get_config
|
|
16
18
|
from magmascript.core.exceptions import MagmascriptError
|
|
17
19
|
from magmascript.core.output import format_output
|
|
18
20
|
|
|
19
21
|
|
|
22
|
+
# -- command registry ----------------------------------------------------
|
|
23
|
+
|
|
24
|
+
COMMANDS: dict[str, Callable] = {}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def register(name: str, help_text: str = "") -> Callable:
|
|
28
|
+
"""Decorator to register a CLI command handler.
|
|
29
|
+
|
|
30
|
+
The handler receives (action, args, fmt).
|
|
31
|
+
"""
|
|
32
|
+
def decorator(fn: Callable) -> Callable:
|
|
33
|
+
COMMANDS[name] = fn
|
|
34
|
+
fn._help_text = help_text
|
|
35
|
+
return fn
|
|
36
|
+
return decorator
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _domain_command(client_cls: type, dispatch_fn: Callable, help_text: str = "") -> Callable:
|
|
40
|
+
"""Create a command handler that manages config, client lifecycle, and dispatch."""
|
|
41
|
+
def handler(action: str, args: list[str], fmt: str) -> None:
|
|
42
|
+
config = get_config()
|
|
43
|
+
client = client_cls(config)
|
|
44
|
+
try:
|
|
45
|
+
dispatch_fn(action, args, client, fmt)
|
|
46
|
+
finally:
|
|
47
|
+
close = getattr(client, "close", None)
|
|
48
|
+
if close:
|
|
49
|
+
close()
|
|
50
|
+
handler._help_text = help_text
|
|
51
|
+
return handler
|
|
52
|
+
|
|
53
|
+
|
|
20
54
|
def _generate_channels_js(channels: list[dict]) -> str:
|
|
21
55
|
"""Generate visual/tv/channels.js from TV channel data."""
|
|
22
56
|
lines = []
|
|
@@ -30,6 +64,212 @@ def _generate_channels_js(channels: list[dict]) -> str:
|
|
|
30
64
|
return 'window.TV_CHANNELS = [\n' + ',\n'.join(lines) + '\n];\n'
|
|
31
65
|
|
|
32
66
|
|
|
67
|
+
# -- register domain commands --------------------------------------------
|
|
68
|
+
|
|
69
|
+
def _register_domains():
|
|
70
|
+
from magmascript.domains.mcp import MCPClient
|
|
71
|
+
from magmascript.domains.pi import PIClient
|
|
72
|
+
from magmascript.domains.mac import MacClient
|
|
73
|
+
from magmascript.domains.mc1 import MC1Client
|
|
74
|
+
from magmascript.domains.gh import GHClient
|
|
75
|
+
from magmascript.domains.media import MediaClient
|
|
76
|
+
from magmascript.domains.scores import ScoresClient
|
|
77
|
+
from magmascript.domains.rights import RightsClient
|
|
78
|
+
from magmascript.domains.archive import ArchiveClient
|
|
79
|
+
from magmascript.domains.mb import MusicBrainzClient
|
|
80
|
+
from magmascript.domains.lastfm import LastFmClient
|
|
81
|
+
from magmascript.domains.search import SearchClient
|
|
82
|
+
|
|
83
|
+
register("mcp")(_domain_command(MCPClient, _dispatch_mcp))
|
|
84
|
+
register("pi")(_domain_command(PIClient, _dispatch_pi))
|
|
85
|
+
register("mac")(_domain_command(MacClient, _dispatch_mac))
|
|
86
|
+
register("mc1")(_domain_command(MC1Client, _dispatch_mc1))
|
|
87
|
+
register("gh")(_domain_command(GHClient, _dispatch_gh))
|
|
88
|
+
register("media")(_domain_command(MediaClient, _dispatch_media))
|
|
89
|
+
register("scores")(_domain_command(ScoresClient, _dispatch_scores))
|
|
90
|
+
register("rights")(_domain_command(RightsClient, _dispatch_rights))
|
|
91
|
+
|
|
92
|
+
def _archive_handler(action, args, fmt):
|
|
93
|
+
from pathlib import Path
|
|
94
|
+
config = get_config()
|
|
95
|
+
project_root = Path(config.project.root) if config.project.root else None
|
|
96
|
+
client = ArchiveClient(project_root=project_root)
|
|
97
|
+
_dispatch_archive(action, args, client, fmt)
|
|
98
|
+
|
|
99
|
+
register("archive", "Archive page operations")(_archive_handler)
|
|
100
|
+
|
|
101
|
+
def _mb_handler(action, args, fmt):
|
|
102
|
+
from pathlib import Path
|
|
103
|
+
config = get_config()
|
|
104
|
+
project_root = Path(config.project.root) if config.project.root else None
|
|
105
|
+
client = MusicBrainzClient(project_root=project_root)
|
|
106
|
+
try:
|
|
107
|
+
_dispatch_mb(action, args, client, fmt)
|
|
108
|
+
finally:
|
|
109
|
+
client.close()
|
|
110
|
+
|
|
111
|
+
register("mb", "MusicBrainz API client")(_mb_handler)
|
|
112
|
+
|
|
113
|
+
def _lastfm_handler(action, args, fmt):
|
|
114
|
+
from pathlib import Path
|
|
115
|
+
config = get_config()
|
|
116
|
+
project_root = Path(config.project.root) if config.project.root else None
|
|
117
|
+
try:
|
|
118
|
+
client = LastFmClient(project_root=project_root)
|
|
119
|
+
except MagmascriptError as e:
|
|
120
|
+
if action and action != "--help":
|
|
121
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
client = None
|
|
124
|
+
try:
|
|
125
|
+
_dispatch_lastfm(action, args, client, fmt)
|
|
126
|
+
finally:
|
|
127
|
+
if client:
|
|
128
|
+
client.close()
|
|
129
|
+
|
|
130
|
+
register("lastfm", "Last.fm API client")(_lastfm_handler)
|
|
131
|
+
|
|
132
|
+
def _search_handler(action, args, fmt):
|
|
133
|
+
from pathlib import Path
|
|
134
|
+
config = get_config()
|
|
135
|
+
project_root = Path(config.project.root) if config.project.root else None
|
|
136
|
+
client = SearchClient(project_root=project_root)
|
|
137
|
+
_dispatch_search(action, args, client, fmt)
|
|
138
|
+
|
|
139
|
+
register("search", "Site search index builder")(_search_handler)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# -- register built-in meta commands ------------------------------------
|
|
143
|
+
|
|
144
|
+
@register("run", "Run a MagmaScript (.mgs) file")
|
|
145
|
+
def _cmd_run(action: str, args: list[str], fmt: str) -> None:
|
|
146
|
+
_dispatch_run(action, args)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@register("repl", "Start interactive MagmaScript REPL")
|
|
150
|
+
def _cmd_repl(action: str, args: list[str], fmt: str) -> None:
|
|
151
|
+
from magmascript.repl import repl
|
|
152
|
+
repl()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@register("configure", "Fetch API key from MCP server")
|
|
156
|
+
def _cmd_configure(action: str, args: list[str], fmt: str) -> None:
|
|
157
|
+
_dispatch_configure(action, args)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@register("magma", "Show system status dashboard")
|
|
161
|
+
def _cmd_magma(action: str, args: list[str], fmt: str) -> None:
|
|
162
|
+
_dispatch_magma(action, fmt)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@register("crunch", "Run a batch pipeline")
|
|
166
|
+
def _cmd_crunch(action: str, args: list[str], fmt: str) -> None:
|
|
167
|
+
_dispatch_crunch(action, args, fmt)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@register("texas", "Full/heavy operation")
|
|
171
|
+
def _cmd_texas(action: str, args: list[str], fmt: str) -> None:
|
|
172
|
+
_dispatch_texas(action, args, fmt)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@register("toast", "Burn/clear caches")
|
|
176
|
+
def _cmd_toast(action: str, args: list[str], fmt: str) -> None:
|
|
177
|
+
_dispatch_toast(action, args, fmt)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@register("cache", "Cache management")
|
|
181
|
+
def _cmd_cache(action: str, args: list[str], fmt: str) -> None:
|
|
182
|
+
_dispatch_cache(action, args, fmt)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@register("codegen", "Generate C code from .mgs files")
|
|
186
|
+
def _cmd_codegen(action: str, args: list[str], fmt: str) -> None:
|
|
187
|
+
"""Dispatch codegen subcommands."""
|
|
188
|
+
if not action or action == "--help":
|
|
189
|
+
print("""Generate C code from MagmaScript (.mgs) files.
|
|
190
|
+
|
|
191
|
+
Usage:
|
|
192
|
+
magmascript codegen <file.mgs> Generate C to stdout
|
|
193
|
+
magmascript codegen <file.mgs> -o out.c Generate C to file
|
|
194
|
+
|
|
195
|
+
Options:
|
|
196
|
+
--help Show this help
|
|
197
|
+
""")
|
|
198
|
+
sys.exit(0)
|
|
199
|
+
|
|
200
|
+
from pathlib import Path
|
|
201
|
+
script_path = Path(action)
|
|
202
|
+
if not script_path.exists():
|
|
203
|
+
print(f"Error: File not found: {script_path}", file=sys.stderr)
|
|
204
|
+
sys.exit(1)
|
|
205
|
+
|
|
206
|
+
if not script_path.suffix == ".mgs":
|
|
207
|
+
print(f"Warning: File does not have .mgs extension: {script_path}", file=sys.stderr)
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
source = script_path.read_text(encoding="utf-8")
|
|
211
|
+
from magmascript.lang.lexer import Lexer
|
|
212
|
+
from magmascript.lang.parser import Parser
|
|
213
|
+
from magmascript.codegen import generate_c
|
|
214
|
+
|
|
215
|
+
filename = str(script_path)
|
|
216
|
+
tokens = Lexer(source, filename=filename).tokenize()
|
|
217
|
+
program = Parser(tokens, source=source, filename=filename).parse()
|
|
218
|
+
|
|
219
|
+
c_code = generate_c(program)
|
|
220
|
+
|
|
221
|
+
# Check for -o flag
|
|
222
|
+
output_file = None
|
|
223
|
+
if "-o" in args:
|
|
224
|
+
idx = args.index("-o")
|
|
225
|
+
if idx + 1 < len(args):
|
|
226
|
+
output_file = args[idx + 1]
|
|
227
|
+
|
|
228
|
+
if output_file:
|
|
229
|
+
Path(output_file).write_text(c_code)
|
|
230
|
+
print(f"Generated {output_file}")
|
|
231
|
+
else:
|
|
232
|
+
print(c_code)
|
|
233
|
+
|
|
234
|
+
except Exception as e:
|
|
235
|
+
if hasattr(e, "format"):
|
|
236
|
+
print(e.format(), file=sys.stderr)
|
|
237
|
+
else:
|
|
238
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
239
|
+
sys.exit(1)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@register("scaffold", "Generate project structures and boilerplate")
|
|
243
|
+
def _cmd_scaffold(action: str, args: list[str], fmt: str) -> None:
|
|
244
|
+
"""Dispatch scaffold subcommands."""
|
|
245
|
+
if not action or action == "--help":
|
|
246
|
+
print("""Generate MagmaScript project structures and boilerplate.
|
|
247
|
+
|
|
248
|
+
Usage:
|
|
249
|
+
magmascript scaffold module <name> Generate a new module with tests
|
|
250
|
+
|
|
251
|
+
Options:
|
|
252
|
+
--help Show this help
|
|
253
|
+
""")
|
|
254
|
+
sys.exit(0)
|
|
255
|
+
|
|
256
|
+
if action == "module":
|
|
257
|
+
if not args:
|
|
258
|
+
print("Error: Module name required. Usage: magmascript scaffold module <name>", file=sys.stderr)
|
|
259
|
+
sys.exit(1)
|
|
260
|
+
|
|
261
|
+
name = args[0]
|
|
262
|
+
from magmascript.scaffold import scaffold_module
|
|
263
|
+
path = scaffold_module(name)
|
|
264
|
+
print(f"Created module: {path}")
|
|
265
|
+
print(f" {path / name}.mgs")
|
|
266
|
+
print(f" {path / 'tests' / f'test_{name}.mgs'}")
|
|
267
|
+
|
|
268
|
+
else:
|
|
269
|
+
print(f"Unknown scaffold type: {action!r}. Available: module", file=sys.stderr)
|
|
270
|
+
sys.exit(1)
|
|
271
|
+
|
|
272
|
+
|
|
33
273
|
def usage():
|
|
34
274
|
print("""magmascript — scripting toolkit with domain-first subcommands
|
|
35
275
|
|
|
@@ -197,147 +437,17 @@ def main():
|
|
|
197
437
|
no_cache = True
|
|
198
438
|
rest.remove("--no-cache")
|
|
199
439
|
|
|
200
|
-
|
|
440
|
+
# Register domain commands (lazy, on first use)
|
|
441
|
+
if not COMMANDS:
|
|
442
|
+
_register_domains()
|
|
201
443
|
|
|
202
444
|
try:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
try:
|
|
207
|
-
_dispatch_mcp(action, rest, client, fmt)
|
|
208
|
-
finally:
|
|
209
|
-
client.close()
|
|
210
|
-
|
|
211
|
-
elif domain == "pi":
|
|
212
|
-
from magmascript.domains.pi import PIClient
|
|
213
|
-
client = PIClient(config)
|
|
214
|
-
try:
|
|
215
|
-
_dispatch_pi(action, rest, client, fmt)
|
|
216
|
-
finally:
|
|
217
|
-
client.close()
|
|
218
|
-
|
|
219
|
-
elif domain == "mac":
|
|
220
|
-
from magmascript.domains.mac import MacClient
|
|
221
|
-
client = MacClient(config)
|
|
222
|
-
try:
|
|
223
|
-
_dispatch_mac(action, rest, client, fmt)
|
|
224
|
-
finally:
|
|
225
|
-
client.close()
|
|
226
|
-
|
|
227
|
-
elif domain == "mc1":
|
|
228
|
-
from magmascript.domains.mc1 import MC1Client
|
|
229
|
-
client = MC1Client(config)
|
|
230
|
-
try:
|
|
231
|
-
_dispatch_mc1(action, rest, client, fmt)
|
|
232
|
-
finally:
|
|
233
|
-
client.close()
|
|
234
|
-
|
|
235
|
-
elif domain == "gh":
|
|
236
|
-
from magmascript.domains.gh import GHClient
|
|
237
|
-
client = GHClient(config)
|
|
238
|
-
try:
|
|
239
|
-
_dispatch_gh(action, rest, client, fmt)
|
|
240
|
-
finally:
|
|
241
|
-
client.close()
|
|
242
|
-
|
|
243
|
-
elif domain == "media":
|
|
244
|
-
from magmascript.domains.media import MediaClient
|
|
245
|
-
client = MediaClient(config)
|
|
246
|
-
try:
|
|
247
|
-
_dispatch_media(action, rest, client, fmt)
|
|
248
|
-
finally:
|
|
249
|
-
client.close()
|
|
250
|
-
|
|
251
|
-
elif domain == "scores":
|
|
252
|
-
from magmascript.domains.scores import ScoresClient
|
|
253
|
-
client = ScoresClient(config)
|
|
254
|
-
try:
|
|
255
|
-
_dispatch_scores(action, rest, client, fmt)
|
|
256
|
-
finally:
|
|
257
|
-
client.close()
|
|
258
|
-
|
|
259
|
-
elif domain == "rights":
|
|
260
|
-
from magmascript.domains.rights import RightsClient
|
|
261
|
-
client = RightsClient(config)
|
|
262
|
-
try:
|
|
263
|
-
_dispatch_rights(action, rest, client, fmt)
|
|
264
|
-
finally:
|
|
265
|
-
client.close()
|
|
266
|
-
|
|
267
|
-
elif domain == "archive":
|
|
268
|
-
from pathlib import Path
|
|
269
|
-
from magmascript.domains.archive import ArchiveClient
|
|
270
|
-
project_root = Path(config.project.root) if config.project.root else None
|
|
271
|
-
client = ArchiveClient(project_root=project_root)
|
|
272
|
-
try:
|
|
273
|
-
_dispatch_archive(action, rest, client, fmt)
|
|
274
|
-
finally:
|
|
275
|
-
pass # ArchiveClient doesn't have a close method
|
|
276
|
-
|
|
277
|
-
elif domain == "mb":
|
|
278
|
-
from pathlib import Path
|
|
279
|
-
from magmascript.domains.mb import MusicBrainzClient
|
|
280
|
-
project_root = Path(config.project.root) if config.project.root else None
|
|
281
|
-
client = MusicBrainzClient(project_root=project_root)
|
|
282
|
-
try:
|
|
283
|
-
_dispatch_mb(action, rest, client, fmt)
|
|
284
|
-
finally:
|
|
285
|
-
client.close()
|
|
286
|
-
|
|
287
|
-
elif domain == "lastfm":
|
|
288
|
-
from pathlib import Path
|
|
289
|
-
from magmascript.domains.lastfm import LastFmClient
|
|
290
|
-
project_root = Path(config.project.root) if config.project.root else None
|
|
291
|
-
try:
|
|
292
|
-
client = LastFmClient(project_root=project_root)
|
|
293
|
-
except MagmascriptError as e:
|
|
294
|
-
if action and action != "--help":
|
|
295
|
-
print(f"Error: {e}", file=sys.stderr)
|
|
296
|
-
sys.exit(1)
|
|
297
|
-
client = None
|
|
298
|
-
try:
|
|
299
|
-
_dispatch_lastfm(action, rest, client, fmt)
|
|
300
|
-
finally:
|
|
301
|
-
if client:
|
|
302
|
-
client.close()
|
|
303
|
-
|
|
304
|
-
elif domain == "search":
|
|
305
|
-
from pathlib import Path
|
|
306
|
-
from magmascript.domains.search import SearchClient
|
|
307
|
-
project_root = Path(config.project.root) if config.project.root else None
|
|
308
|
-
client = SearchClient(project_root=project_root)
|
|
309
|
-
try:
|
|
310
|
-
_dispatch_search(action, rest, client, fmt)
|
|
311
|
-
finally:
|
|
312
|
-
pass # SearchClient doesn't have a close method
|
|
313
|
-
|
|
314
|
-
elif domain == "cache":
|
|
315
|
-
_dispatch_cache(action, rest, fmt)
|
|
316
|
-
|
|
317
|
-
elif domain == "run":
|
|
318
|
-
_dispatch_run(action, rest)
|
|
319
|
-
|
|
320
|
-
elif domain == "repl":
|
|
321
|
-
from magmascript.repl import repl
|
|
322
|
-
repl()
|
|
323
|
-
|
|
324
|
-
elif domain == "configure":
|
|
325
|
-
_dispatch_configure(action, rest)
|
|
326
|
-
|
|
327
|
-
elif domain == "magma":
|
|
328
|
-
_dispatch_magma(action, fmt)
|
|
329
|
-
|
|
330
|
-
elif domain == "crunch":
|
|
331
|
-
_dispatch_crunch(action, rest, fmt)
|
|
332
|
-
|
|
333
|
-
elif domain == "texas":
|
|
334
|
-
_dispatch_texas(action, rest, fmt)
|
|
335
|
-
|
|
336
|
-
elif domain == "toast":
|
|
337
|
-
_dispatch_toast(action, rest, fmt)
|
|
338
|
-
|
|
445
|
+
cmd = COMMANDS.get(domain)
|
|
446
|
+
if cmd:
|
|
447
|
+
cmd(action, rest, fmt)
|
|
339
448
|
else:
|
|
340
|
-
|
|
449
|
+
available = ", ".join(sorted(COMMANDS.keys()))
|
|
450
|
+
print(f"Unknown domain: {domain!r}. Available: {available}", file=sys.stderr)
|
|
341
451
|
sys.exit(1)
|
|
342
452
|
|
|
343
453
|
except KeyboardInterrupt:
|