magmascript 2.1.0__tar.gz → 2.2.0__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-2.1.0 → magmascript-2.2.0}/PKG-INFO +44 -4
- {magmascript-2.1.0 → magmascript-2.2.0}/README.md +43 -3
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/__init__.py +4 -2
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/config.py +14 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/__init__.py +2 -1
- magmascript-2.2.0/magmascript/domains/mc1/__init__.py +14 -0
- magmascript-2.2.0/magmascript/domains/mc1/client.py +122 -0
- magmascript-2.2.0/magmascript/domains/mc1/tools.py +82 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/PKG-INFO +44 -4
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/SOURCES.txt +3 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/pyproject.toml +1 -1
- {magmascript-2.1.0 → magmascript-2.2.0}/LICENSE +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/cli.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/cache.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/commands.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/exceptions.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/github.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/output.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/registry.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/rpc.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/core/runner.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/archive/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/archive/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/gh/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/gh/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/gh/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/lastfm/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/lastfm/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/mb/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/mb/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/mcp/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/mcp/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/mcp/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/archive.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/met_museum.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/openverse.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/pexels.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/pixabay.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/providers/smithsonian.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/media/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/pi/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/pi/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/pi/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/rights/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/rights/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/rights/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/scores/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/scores/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/scores/tools.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/search/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/domains/search/client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/__init__.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/ast_nodes.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/builtins.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/domain_bridge.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/environment.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/interpreter.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/lexer.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/parser.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/pygments_mgs.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/tokens.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/lang/util.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript/repl.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/dependency_links.txt +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/entry_points.txt +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/requires.txt +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/magmascript.egg-info/top_level.txt +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/setup.cfg +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_cache.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_classes.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_cli.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_commands.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_domain_bridge.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_import.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_lang.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_mcp_client.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_rpc.py +0 -0
- {magmascript-2.1.0 → magmascript-2.2.0}/tests/test_try_catch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: magmascript
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Scripting toolkit with domain-first subcommands
|
|
5
5
|
Author: Jake McCoy
|
|
6
6
|
License-Expression: MIT
|
|
@@ -85,11 +85,14 @@ Write `.mgs` scripts using a Python-inspired mini language with direct access to
|
|
|
85
85
|
### Quick Start
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
# Run a script
|
|
89
|
-
magmascript
|
|
88
|
+
# Run a script (shorthand)
|
|
89
|
+
magmascript scripts/examples/hello.mgs
|
|
90
90
|
|
|
91
91
|
# Run with arguments
|
|
92
|
-
magmascript
|
|
92
|
+
magmascript scripts/examples/top-scores.mgs tetris
|
|
93
|
+
|
|
94
|
+
# Or use the explicit run subcommand
|
|
95
|
+
magmascript run scripts/examples/hello.mgs
|
|
93
96
|
|
|
94
97
|
# Start interactive REPL
|
|
95
98
|
magmascript repl
|
|
@@ -289,6 +292,7 @@ if "xyz" not in "hello" { ... }
|
|
|
289
292
|
| Function | Description |
|
|
290
293
|
|----------|-------------|
|
|
291
294
|
| `print(...)` | Print to stdout |
|
|
295
|
+
| `echo(...)` | Print to stdout (alias for print) |
|
|
292
296
|
| `len(x)` | Length of string, list, or dict |
|
|
293
297
|
| `type(x)` | Type name as string |
|
|
294
298
|
| `range(n)`, `range(start, stop)`, `range(start, stop, step)` | Generate integer ranges |
|
|
@@ -338,6 +342,32 @@ See `scripts/examples/` for working examples:
|
|
|
338
342
|
| `real-domains.mgs` | Test real domain connections (MCP search, scoreboards, games) |
|
|
339
343
|
| `domain-example.mgs` | Domain object overview and usage patterns |
|
|
340
344
|
|
|
345
|
+
### REPL
|
|
346
|
+
|
|
347
|
+
Start an interactive MagmaScript session:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
magmascript repl
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Features:**
|
|
354
|
+
- Syntax highlighting via Pygments
|
|
355
|
+
- Tab completion for keywords, builtins, domain methods, and user-defined variables
|
|
356
|
+
- Persistent history across sessions (`~/.magmascript_history`)
|
|
357
|
+
- Multiline editing with proper continuation prompts
|
|
358
|
+
- Dot-commands:
|
|
359
|
+
|
|
360
|
+
| Command | Description |
|
|
361
|
+
|---------|-------------|
|
|
362
|
+
| `.help` | Show available commands |
|
|
363
|
+
| `.exit` | Exit the REPL |
|
|
364
|
+
| `.clear` | Clear the screen |
|
|
365
|
+
| `.ast` | Show AST for last expression |
|
|
366
|
+
| `.magma` | System status dashboard |
|
|
367
|
+
| `.crunch <target>` | Run batch pipeline |
|
|
368
|
+
| `.texas <target>` | Full/heavy operation |
|
|
369
|
+
| `.toast <target>` | Burn/clear caches |
|
|
370
|
+
|
|
341
371
|
## Domains
|
|
342
372
|
|
|
343
373
|
### MCP Domain — MusicBrainz, scores, Discogs, write operations
|
|
@@ -363,6 +393,14 @@ magmascript pi backup musicbrainz # backup + commit to GitHub
|
|
|
363
393
|
magmascript pi traffic # nginx traffic analysis
|
|
364
394
|
```
|
|
365
395
|
|
|
396
|
+
### MC1 Domain — Windows PC management (via SSH)
|
|
397
|
+
```bash
|
|
398
|
+
magmascript mc1 status # all running Windows services
|
|
399
|
+
magmascript mc1 info # uptime, memory, CPU, disk
|
|
400
|
+
magmascript mc1 restart OllamaSvc # restart a Windows service
|
|
401
|
+
magmascript mc1 processes # top processes by CPU
|
|
402
|
+
```
|
|
403
|
+
|
|
366
404
|
### GitHub Domain — Direct API access
|
|
367
405
|
```bash
|
|
368
406
|
magmascript gh workflows # all workflow statuses
|
|
@@ -385,6 +423,7 @@ magmascript scores reset tetris # reset one game (backup created)
|
|
|
385
423
|
```bash
|
|
386
424
|
magmascript archive check-format # validate HTML formatting
|
|
387
425
|
magmascript archive bake-cache # inline MusicBrainz cache into pages
|
|
426
|
+
magmascript archive generate-stubs # generate stub HTML for new entities
|
|
388
427
|
```
|
|
389
428
|
|
|
390
429
|
### MusicBrainz Domain — MusicBrainz API client
|
|
@@ -511,6 +550,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunchmedia/magmascript
|
|
|
511
550
|
- [Last.fm Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Last.fm-Domain)
|
|
512
551
|
- [MusicBrainz Domain](https://github.com/magmacrunchmedia/magmascript/wiki/MusicBrainz-Domain)
|
|
513
552
|
- [Search Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Search-Domain)
|
|
553
|
+
- [Media Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Media-Domain)
|
|
514
554
|
- [Example Scripts](https://github.com/magmacrunchmedia/magmascript/wiki/Example-Scripts)
|
|
515
555
|
- [Architecture](https://github.com/magmacrunchmedia/magmascript/wiki/Architecture)
|
|
516
556
|
|
|
@@ -50,11 +50,14 @@ Write `.mgs` scripts using a Python-inspired mini language with direct access to
|
|
|
50
50
|
### Quick Start
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
# Run a script
|
|
54
|
-
magmascript
|
|
53
|
+
# Run a script (shorthand)
|
|
54
|
+
magmascript scripts/examples/hello.mgs
|
|
55
55
|
|
|
56
56
|
# Run with arguments
|
|
57
|
-
magmascript
|
|
57
|
+
magmascript scripts/examples/top-scores.mgs tetris
|
|
58
|
+
|
|
59
|
+
# Or use the explicit run subcommand
|
|
60
|
+
magmascript run scripts/examples/hello.mgs
|
|
58
61
|
|
|
59
62
|
# Start interactive REPL
|
|
60
63
|
magmascript repl
|
|
@@ -254,6 +257,7 @@ if "xyz" not in "hello" { ... }
|
|
|
254
257
|
| Function | Description |
|
|
255
258
|
|----------|-------------|
|
|
256
259
|
| `print(...)` | Print to stdout |
|
|
260
|
+
| `echo(...)` | Print to stdout (alias for print) |
|
|
257
261
|
| `len(x)` | Length of string, list, or dict |
|
|
258
262
|
| `type(x)` | Type name as string |
|
|
259
263
|
| `range(n)`, `range(start, stop)`, `range(start, stop, step)` | Generate integer ranges |
|
|
@@ -303,6 +307,32 @@ See `scripts/examples/` for working examples:
|
|
|
303
307
|
| `real-domains.mgs` | Test real domain connections (MCP search, scoreboards, games) |
|
|
304
308
|
| `domain-example.mgs` | Domain object overview and usage patterns |
|
|
305
309
|
|
|
310
|
+
### REPL
|
|
311
|
+
|
|
312
|
+
Start an interactive MagmaScript session:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
magmascript repl
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Features:**
|
|
319
|
+
- Syntax highlighting via Pygments
|
|
320
|
+
- Tab completion for keywords, builtins, domain methods, and user-defined variables
|
|
321
|
+
- Persistent history across sessions (`~/.magmascript_history`)
|
|
322
|
+
- Multiline editing with proper continuation prompts
|
|
323
|
+
- Dot-commands:
|
|
324
|
+
|
|
325
|
+
| Command | Description |
|
|
326
|
+
|---------|-------------|
|
|
327
|
+
| `.help` | Show available commands |
|
|
328
|
+
| `.exit` | Exit the REPL |
|
|
329
|
+
| `.clear` | Clear the screen |
|
|
330
|
+
| `.ast` | Show AST for last expression |
|
|
331
|
+
| `.magma` | System status dashboard |
|
|
332
|
+
| `.crunch <target>` | Run batch pipeline |
|
|
333
|
+
| `.texas <target>` | Full/heavy operation |
|
|
334
|
+
| `.toast <target>` | Burn/clear caches |
|
|
335
|
+
|
|
306
336
|
## Domains
|
|
307
337
|
|
|
308
338
|
### MCP Domain — MusicBrainz, scores, Discogs, write operations
|
|
@@ -328,6 +358,14 @@ magmascript pi backup musicbrainz # backup + commit to GitHub
|
|
|
328
358
|
magmascript pi traffic # nginx traffic analysis
|
|
329
359
|
```
|
|
330
360
|
|
|
361
|
+
### MC1 Domain — Windows PC management (via SSH)
|
|
362
|
+
```bash
|
|
363
|
+
magmascript mc1 status # all running Windows services
|
|
364
|
+
magmascript mc1 info # uptime, memory, CPU, disk
|
|
365
|
+
magmascript mc1 restart OllamaSvc # restart a Windows service
|
|
366
|
+
magmascript mc1 processes # top processes by CPU
|
|
367
|
+
```
|
|
368
|
+
|
|
331
369
|
### GitHub Domain — Direct API access
|
|
332
370
|
```bash
|
|
333
371
|
magmascript gh workflows # all workflow statuses
|
|
@@ -350,6 +388,7 @@ magmascript scores reset tetris # reset one game (backup created)
|
|
|
350
388
|
```bash
|
|
351
389
|
magmascript archive check-format # validate HTML formatting
|
|
352
390
|
magmascript archive bake-cache # inline MusicBrainz cache into pages
|
|
391
|
+
magmascript archive generate-stubs # generate stub HTML for new entities
|
|
353
392
|
```
|
|
354
393
|
|
|
355
394
|
### MusicBrainz Domain — MusicBrainz API client
|
|
@@ -476,6 +515,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunchmedia/magmascript
|
|
|
476
515
|
- [Last.fm Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Last.fm-Domain)
|
|
477
516
|
- [MusicBrainz Domain](https://github.com/magmacrunchmedia/magmascript/wiki/MusicBrainz-Domain)
|
|
478
517
|
- [Search Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Search-Domain)
|
|
518
|
+
- [Media Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Media-Domain)
|
|
479
519
|
- [Example Scripts](https://github.com/magmacrunchmedia/magmascript/wiki/Example-Scripts)
|
|
480
520
|
- [Architecture](https://github.com/magmacrunchmedia/magmascript/wiki/Architecture)
|
|
481
521
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""magmascript — a scripting toolkit with domain-first subcommands."""
|
|
2
2
|
|
|
3
|
-
__version__ = "2.0
|
|
3
|
+
__version__ = "2.2.0"
|
|
4
4
|
|
|
5
|
-
from magmascript.core.config import Config, GHConfig, MediaConfig, PIConfig, get_config, load_config, set_config
|
|
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
|
|
7
7
|
from magmascript.core.rpc import RPCClient, RPCError, RPCResponse
|
|
8
8
|
from magmascript.core.runner import CommandRunner
|
|
@@ -14,6 +14,7 @@ from magmascript import domains # noqa: F401
|
|
|
14
14
|
# Convenience: expose clients at top level
|
|
15
15
|
from magmascript.domains.mcp import MCPClient
|
|
16
16
|
from magmascript.domains.pi import PIClient
|
|
17
|
+
from magmascript.domains.mc1 import MC1Client
|
|
17
18
|
from magmascript.domains.gh import GHClient
|
|
18
19
|
from magmascript.domains.media import MediaClient
|
|
19
20
|
from magmascript.domains.rights import RightsClient
|
|
@@ -27,6 +28,7 @@ __all__ = [
|
|
|
27
28
|
"Config",
|
|
28
29
|
"GHClient",
|
|
29
30
|
"GHConfig",
|
|
31
|
+
"MC1Client",
|
|
30
32
|
"MCPClient",
|
|
31
33
|
"MediaClient",
|
|
32
34
|
"MediaConfig",
|
|
@@ -31,6 +31,14 @@ class PIConfig:
|
|
|
31
31
|
user: str = "jake"
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
@dataclass
|
|
35
|
+
class MC1Config:
|
|
36
|
+
"""MC1 Windows PC SSH configuration."""
|
|
37
|
+
|
|
38
|
+
host: str = "100.75.220.87"
|
|
39
|
+
user: str = "magma"
|
|
40
|
+
|
|
41
|
+
|
|
34
42
|
@dataclass
|
|
35
43
|
class GHConfig:
|
|
36
44
|
"""GitHub API configuration."""
|
|
@@ -79,6 +87,7 @@ class Config:
|
|
|
79
87
|
|
|
80
88
|
mcp: MCPConfig = field(default_factory=MCPConfig)
|
|
81
89
|
pi: PIConfig = field(default_factory=PIConfig)
|
|
90
|
+
mc1: MC1Config = field(default_factory=MC1Config)
|
|
82
91
|
gh: GHConfig = field(default_factory=GHConfig)
|
|
83
92
|
media: MediaConfig = field(default_factory=MediaConfig)
|
|
84
93
|
cache: CacheConfig = field(default_factory=CacheConfig)
|
|
@@ -112,6 +121,7 @@ def load_config(*, config_path: Path | None = None, env_prefix: str = "MAGMA_")
|
|
|
112
121
|
toml = _load_toml(cfg_file)
|
|
113
122
|
mcp_section = toml.get("mcp", {})
|
|
114
123
|
pi_section = toml.get("pi", {})
|
|
124
|
+
mc1_section = toml.get("mc1", {})
|
|
115
125
|
gh_section = toml.get("gh", {})
|
|
116
126
|
media_section = toml.get("media", {})
|
|
117
127
|
cache_section = toml.get("cache", {})
|
|
@@ -129,6 +139,10 @@ def load_config(*, config_path: Path | None = None, env_prefix: str = "MAGMA_")
|
|
|
129
139
|
host=os.environ.get(f"{env_prefix}PI_HOST", pi_section.get("host", "192.168.1.16")),
|
|
130
140
|
user=os.environ.get(f"{env_prefix}PI_USER", pi_section.get("user", "jake")),
|
|
131
141
|
),
|
|
142
|
+
mc1=MC1Config(
|
|
143
|
+
host=os.environ.get(f"{env_prefix}MC1_HOST", mc1_section.get("host", "100.75.220.87")),
|
|
144
|
+
user=os.environ.get(f"{env_prefix}MC1_USER", mc1_section.get("user", "magma")),
|
|
145
|
+
),
|
|
132
146
|
gh=GHConfig(
|
|
133
147
|
token=os.environ.get(f"{env_prefix}GH_TOKEN")
|
|
134
148
|
or os.environ.get("GITHUB_TOKEN", "")
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Importing this package triggers domain registration
|
|
4
4
|
from magmascript.domains import mcp # noqa: F401
|
|
5
5
|
from magmascript.domains import pi # noqa: F401
|
|
6
|
+
from magmascript.domains import mc1 # noqa: F401
|
|
6
7
|
from magmascript.domains import gh # noqa: F401
|
|
7
8
|
from magmascript.domains import media # noqa: F401
|
|
8
9
|
from magmascript.domains import scores # noqa: F401
|
|
@@ -12,4 +13,4 @@ from magmascript.domains import mb # noqa: F401
|
|
|
12
13
|
from magmascript.domains import lastfm # noqa: F401
|
|
13
14
|
from magmascript.domains import search # noqa: F401
|
|
14
15
|
|
|
15
|
-
__all__ = ["mcp", "pi", "gh", "media", "scores", "rights", "archive", "mb", "lastfm", "search"]
|
|
16
|
+
__all__ = ["mcp", "pi", "mc1", "gh", "media", "scores", "rights", "archive", "mb", "lastfm", "search"]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""MC1 domain — exposes MC1Client and registers with the domain registry."""
|
|
2
|
+
|
|
3
|
+
from magmascript.domains.mc1.client import MC1Client
|
|
4
|
+
from magmascript.domains.mc1.tools import MC1ServiceStatus, MC1SystemInfo
|
|
5
|
+
from magmascript.core.registry import register_domain
|
|
6
|
+
|
|
7
|
+
# Register this domain
|
|
8
|
+
register_domain("mc1", MC1Client)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"MC1Client",
|
|
12
|
+
"MC1ServiceStatus",
|
|
13
|
+
"MC1SystemInfo",
|
|
14
|
+
]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""MC1 domain — direct client for Windows PC management.
|
|
2
|
+
|
|
3
|
+
Supports SSH (remote) execution mode for managing MC1.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from magmascript.core.config import Config, get_config
|
|
9
|
+
from magmascript.core.runner import CommandRunner
|
|
10
|
+
from magmascript.domains.mc1.tools import (
|
|
11
|
+
MC1ServiceStatus,
|
|
12
|
+
MC1SystemInfo,
|
|
13
|
+
parse_service_list,
|
|
14
|
+
parse_system_info,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MC1Client:
|
|
19
|
+
"""Direct client for MC1 Windows PC management.
|
|
20
|
+
|
|
21
|
+
Commands run via SSH using PowerShell.
|
|
22
|
+
Raises SSHError on connection or command failures.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, config: Config | None = None, *, local: bool = False):
|
|
26
|
+
cfg = config or get_config()
|
|
27
|
+
self._host = cfg.mc1.host
|
|
28
|
+
self._user = cfg.mc1.user
|
|
29
|
+
self._local = local
|
|
30
|
+
self._runner = CommandRunner(cfg.mc1.host, cfg.mc1.user, local=local)
|
|
31
|
+
|
|
32
|
+
# ------------------------------------------------------------------
|
|
33
|
+
# Service management
|
|
34
|
+
# ------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
def services(self) -> list[MC1ServiceStatus]:
|
|
37
|
+
"""Get status of all running Windows services.
|
|
38
|
+
|
|
39
|
+
Raises SSHError on connection failure.
|
|
40
|
+
"""
|
|
41
|
+
stdout = self._runner.run(
|
|
42
|
+
'powershell -Command "Get-Service | Where-Object {$_.Status -eq \\"Running\\"} | '
|
|
43
|
+
'Select-Object -Property Name, Status | ForEach-Object { \\"$($_.Name): $($_.Status)\\" }"'
|
|
44
|
+
)
|
|
45
|
+
return parse_service_list(stdout)
|
|
46
|
+
|
|
47
|
+
def restart(self, service: str) -> str:
|
|
48
|
+
"""Restart a Windows service.
|
|
49
|
+
|
|
50
|
+
Raises SSHError on connection failure.
|
|
51
|
+
"""
|
|
52
|
+
self._runner.run(
|
|
53
|
+
f'powershell -Command "Restart-Service -Name \\"{service}\\" -Force"',
|
|
54
|
+
timeout=30,
|
|
55
|
+
)
|
|
56
|
+
return f"✓ {service} restarted"
|
|
57
|
+
|
|
58
|
+
# ------------------------------------------------------------------
|
|
59
|
+
# System info
|
|
60
|
+
# ------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
def info(self) -> MC1SystemInfo:
|
|
63
|
+
"""Get MC1 system info (uptime, memory, CPU, disk).
|
|
64
|
+
|
|
65
|
+
Raises SSHError on connection failure.
|
|
66
|
+
"""
|
|
67
|
+
stdout = self._runner.run(
|
|
68
|
+
'powershell -Command "'
|
|
69
|
+
'$os = Get-CimInstance Win32_OperatingSystem; '
|
|
70
|
+
'$cpu = Get-CimInstance Win32_Processor; '
|
|
71
|
+
'$disk = Get-CimInstance Win32_LogicalDisk -Filter \\"DriveType=3\\"; '
|
|
72
|
+
'Write-Host \\"HOSTNAME:$(hostname)\\"; '
|
|
73
|
+
'Write-Host \\"UPTIME:$((Get-Date) - $os.LastBootUpTime)\\"; '
|
|
74
|
+
'Write-Host \\"MEMORY:$([math]::Round($os.TotalVisibleMemorySize/1MB, 1))GB/$([math]::Round(($os.TotalVisibleMemorySize - $os.FreePhysicalMemory)/1MB, 1))GB\\"; '
|
|
75
|
+
'Write-Host \\"CPU:$($cpu.LoadPercentage)%\\"; '
|
|
76
|
+
'Write-Host \\"DISK:$([math]::Round($disk.FreeSpace/$disk.Size*100, 1))% free\\"'
|
|
77
|
+
'"'
|
|
78
|
+
)
|
|
79
|
+
return parse_system_info(stdout)
|
|
80
|
+
|
|
81
|
+
# ------------------------------------------------------------------
|
|
82
|
+
# Processes
|
|
83
|
+
# ------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
def processes(self) -> str:
|
|
86
|
+
"""Get top processes on MC1 by CPU usage.
|
|
87
|
+
|
|
88
|
+
Raises SSHError on connection failure.
|
|
89
|
+
"""
|
|
90
|
+
return self._runner.run(
|
|
91
|
+
'powershell -Command "Get-Process | Sort-Object CPU -Descending | '
|
|
92
|
+
'Select-Object -First 15 Name, CPU, WorkingSet | Format-Table -AutoSize"'
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# ------------------------------------------------------------------
|
|
96
|
+
# Power
|
|
97
|
+
# ------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def reboot(self) -> str:
|
|
100
|
+
"""Reboot MC1.
|
|
101
|
+
|
|
102
|
+
Raises SSHError on connection failure.
|
|
103
|
+
"""
|
|
104
|
+
self._runner.run(
|
|
105
|
+
'powershell -Command "Restart-Computer -Force"',
|
|
106
|
+
timeout=10,
|
|
107
|
+
)
|
|
108
|
+
return "✓ Rebooting MC1..."
|
|
109
|
+
|
|
110
|
+
# ------------------------------------------------------------------
|
|
111
|
+
# Lifecycle
|
|
112
|
+
# ------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
def close(self):
|
|
115
|
+
"""No-op."""
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
def __enter__(self):
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
def __exit__(self, *args):
|
|
122
|
+
self.close()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Typed result dataclasses for the MC1 domain."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class MC1ServiceStatus:
|
|
10
|
+
"""Status of a Windows service."""
|
|
11
|
+
|
|
12
|
+
name: str
|
|
13
|
+
status: str
|
|
14
|
+
ok: bool
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class MC1SystemInfo:
|
|
19
|
+
"""MC1 system info."""
|
|
20
|
+
|
|
21
|
+
hostname: str
|
|
22
|
+
uptime: str
|
|
23
|
+
memory: str
|
|
24
|
+
cpu_load: str
|
|
25
|
+
disk_free: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Parsers
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def parse_service_list(text: str) -> list[MC1ServiceStatus]:
|
|
34
|
+
"""Parse PowerShell Get-Service output into MC1ServiceStatus list.
|
|
35
|
+
|
|
36
|
+
Expected format (from the PowerShell command):
|
|
37
|
+
AmdPpkgSvc: Running
|
|
38
|
+
AppIDSvc: Running
|
|
39
|
+
"""
|
|
40
|
+
results = []
|
|
41
|
+
for line in text.splitlines():
|
|
42
|
+
line = line.strip()
|
|
43
|
+
if ":" in line:
|
|
44
|
+
name, status = line.split(":", 1)
|
|
45
|
+
name = name.strip()
|
|
46
|
+
status = status.strip()
|
|
47
|
+
results.append(MC1ServiceStatus(
|
|
48
|
+
name=name,
|
|
49
|
+
status=status,
|
|
50
|
+
ok=status.lower() == "running",
|
|
51
|
+
))
|
|
52
|
+
return results
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_system_info(text: str) -> MC1SystemInfo:
|
|
56
|
+
"""Parse the output of the combined system info command.
|
|
57
|
+
|
|
58
|
+
Expected format:
|
|
59
|
+
HOSTNAME:MC1
|
|
60
|
+
UPTIME:07:33:06.0140847
|
|
61
|
+
MEMORY:31.7GB/7.6GB
|
|
62
|
+
CPU:4%
|
|
63
|
+
DISK:93.2% free
|
|
64
|
+
"""
|
|
65
|
+
info = {"hostname": "", "uptime": "", "memory": "", "cpu_load": "", "disk_free": ""}
|
|
66
|
+
for line in text.splitlines():
|
|
67
|
+
line = line.strip()
|
|
68
|
+
if ":" in line:
|
|
69
|
+
key, val = line.split(":", 1)
|
|
70
|
+
key = key.lower().strip()
|
|
71
|
+
val = val.strip()
|
|
72
|
+
if key == "hostname":
|
|
73
|
+
info["hostname"] = val
|
|
74
|
+
elif key == "uptime":
|
|
75
|
+
info["uptime"] = val
|
|
76
|
+
elif key == "memory":
|
|
77
|
+
info["memory"] = val
|
|
78
|
+
elif key == "cpu":
|
|
79
|
+
info["cpu_load"] = val
|
|
80
|
+
elif key == "disk":
|
|
81
|
+
info["disk_free"] = val
|
|
82
|
+
return MC1SystemInfo(**info)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: magmascript
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Scripting toolkit with domain-first subcommands
|
|
5
5
|
Author: Jake McCoy
|
|
6
6
|
License-Expression: MIT
|
|
@@ -85,11 +85,14 @@ Write `.mgs` scripts using a Python-inspired mini language with direct access to
|
|
|
85
85
|
### Quick Start
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
# Run a script
|
|
89
|
-
magmascript
|
|
88
|
+
# Run a script (shorthand)
|
|
89
|
+
magmascript scripts/examples/hello.mgs
|
|
90
90
|
|
|
91
91
|
# Run with arguments
|
|
92
|
-
magmascript
|
|
92
|
+
magmascript scripts/examples/top-scores.mgs tetris
|
|
93
|
+
|
|
94
|
+
# Or use the explicit run subcommand
|
|
95
|
+
magmascript run scripts/examples/hello.mgs
|
|
93
96
|
|
|
94
97
|
# Start interactive REPL
|
|
95
98
|
magmascript repl
|
|
@@ -289,6 +292,7 @@ if "xyz" not in "hello" { ... }
|
|
|
289
292
|
| Function | Description |
|
|
290
293
|
|----------|-------------|
|
|
291
294
|
| `print(...)` | Print to stdout |
|
|
295
|
+
| `echo(...)` | Print to stdout (alias for print) |
|
|
292
296
|
| `len(x)` | Length of string, list, or dict |
|
|
293
297
|
| `type(x)` | Type name as string |
|
|
294
298
|
| `range(n)`, `range(start, stop)`, `range(start, stop, step)` | Generate integer ranges |
|
|
@@ -338,6 +342,32 @@ See `scripts/examples/` for working examples:
|
|
|
338
342
|
| `real-domains.mgs` | Test real domain connections (MCP search, scoreboards, games) |
|
|
339
343
|
| `domain-example.mgs` | Domain object overview and usage patterns |
|
|
340
344
|
|
|
345
|
+
### REPL
|
|
346
|
+
|
|
347
|
+
Start an interactive MagmaScript session:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
magmascript repl
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Features:**
|
|
354
|
+
- Syntax highlighting via Pygments
|
|
355
|
+
- Tab completion for keywords, builtins, domain methods, and user-defined variables
|
|
356
|
+
- Persistent history across sessions (`~/.magmascript_history`)
|
|
357
|
+
- Multiline editing with proper continuation prompts
|
|
358
|
+
- Dot-commands:
|
|
359
|
+
|
|
360
|
+
| Command | Description |
|
|
361
|
+
|---------|-------------|
|
|
362
|
+
| `.help` | Show available commands |
|
|
363
|
+
| `.exit` | Exit the REPL |
|
|
364
|
+
| `.clear` | Clear the screen |
|
|
365
|
+
| `.ast` | Show AST for last expression |
|
|
366
|
+
| `.magma` | System status dashboard |
|
|
367
|
+
| `.crunch <target>` | Run batch pipeline |
|
|
368
|
+
| `.texas <target>` | Full/heavy operation |
|
|
369
|
+
| `.toast <target>` | Burn/clear caches |
|
|
370
|
+
|
|
341
371
|
## Domains
|
|
342
372
|
|
|
343
373
|
### MCP Domain — MusicBrainz, scores, Discogs, write operations
|
|
@@ -363,6 +393,14 @@ magmascript pi backup musicbrainz # backup + commit to GitHub
|
|
|
363
393
|
magmascript pi traffic # nginx traffic analysis
|
|
364
394
|
```
|
|
365
395
|
|
|
396
|
+
### MC1 Domain — Windows PC management (via SSH)
|
|
397
|
+
```bash
|
|
398
|
+
magmascript mc1 status # all running Windows services
|
|
399
|
+
magmascript mc1 info # uptime, memory, CPU, disk
|
|
400
|
+
magmascript mc1 restart OllamaSvc # restart a Windows service
|
|
401
|
+
magmascript mc1 processes # top processes by CPU
|
|
402
|
+
```
|
|
403
|
+
|
|
366
404
|
### GitHub Domain — Direct API access
|
|
367
405
|
```bash
|
|
368
406
|
magmascript gh workflows # all workflow statuses
|
|
@@ -385,6 +423,7 @@ magmascript scores reset tetris # reset one game (backup created)
|
|
|
385
423
|
```bash
|
|
386
424
|
magmascript archive check-format # validate HTML formatting
|
|
387
425
|
magmascript archive bake-cache # inline MusicBrainz cache into pages
|
|
426
|
+
magmascript archive generate-stubs # generate stub HTML for new entities
|
|
388
427
|
```
|
|
389
428
|
|
|
390
429
|
### MusicBrainz Domain — MusicBrainz API client
|
|
@@ -511,6 +550,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunchmedia/magmascript
|
|
|
511
550
|
- [Last.fm Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Last.fm-Domain)
|
|
512
551
|
- [MusicBrainz Domain](https://github.com/magmacrunchmedia/magmascript/wiki/MusicBrainz-Domain)
|
|
513
552
|
- [Search Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Search-Domain)
|
|
553
|
+
- [Media Domain](https://github.com/magmacrunchmedia/magmascript/wiki/Media-Domain)
|
|
514
554
|
- [Example Scripts](https://github.com/magmacrunchmedia/magmascript/wiki/Example-Scripts)
|
|
515
555
|
- [Architecture](https://github.com/magmacrunchmedia/magmascript/wiki/Architecture)
|
|
516
556
|
|
|
@@ -30,6 +30,9 @@ magmascript/domains/lastfm/__init__.py
|
|
|
30
30
|
magmascript/domains/lastfm/client.py
|
|
31
31
|
magmascript/domains/mb/__init__.py
|
|
32
32
|
magmascript/domains/mb/client.py
|
|
33
|
+
magmascript/domains/mc1/__init__.py
|
|
34
|
+
magmascript/domains/mc1/client.py
|
|
35
|
+
magmascript/domains/mc1/tools.py
|
|
33
36
|
magmascript/domains/mcp/__init__.py
|
|
34
37
|
magmascript/domains/mcp/client.py
|
|
35
38
|
magmascript/domains/mcp/tools.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|