herm-tui 1.8.2-dev.8 → 1.9.0-dev.2
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/README.md +16 -0
- package/assets/plugins/eikon/__init__.py +17 -0
- package/assets/plugins/eikon/plugin.yaml +7 -0
- package/assets/plugins/eikon/schemas.py +41 -0
- package/assets/plugins/eikon/tools.py +69 -0
- package/index.js +95 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,6 +91,22 @@ See [`.env.example`](./.env.example) for rarely-needed overrides.
|
|
|
91
91
|
- Open board and task detail views, inspect diagnostics, and dispatch work from
|
|
92
92
|
the same shell you use for chat.
|
|
93
93
|
|
|
94
|
+
### Share and install eikons
|
|
95
|
+
|
|
96
|
+
- Press `M` from Gallery to enter the native Eikon Marketplace.
|
|
97
|
+
- Search shared catalog entries, preview the selected eikon, install without
|
|
98
|
+
activating, then use it when ready.
|
|
99
|
+
- Use `eikon.liftaris.dev` as a discovery mirror only; it previews catalog
|
|
100
|
+
entries and points back to Herm for native install/use.
|
|
101
|
+
- Submit local non-bundled eikons for review with `u`; Herm shows the exact
|
|
102
|
+
preflight bundle before submission and blocks published marketplace installs
|
|
103
|
+
from duplicate review submission.
|
|
104
|
+
|
|
105
|
+
Herm owns native Marketplace behavior. The eikon repo owns the registry,
|
|
106
|
+
browser mirror, shared catalog/player exports, install resolver, and publish
|
|
107
|
+
preflight. Herm imports public eikon package exports rather than browser mirror
|
|
108
|
+
internals or unexported source paths.
|
|
109
|
+
|
|
94
110
|
### Customize the shell
|
|
95
111
|
|
|
96
112
|
- Press `Ctrl+K` for the command palette.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Eikon install plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .schemas import EIKON_INSTALL_SCHEMA
|
|
6
|
+
from .tools import _handle_eikon_install, check_herm_available
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def register(ctx) -> None:
|
|
10
|
+
ctx.register_tool(
|
|
11
|
+
name="eikon_install",
|
|
12
|
+
toolset="eikon",
|
|
13
|
+
schema=EIKON_INSTALL_SCHEMA,
|
|
14
|
+
handler=_handle_eikon_install,
|
|
15
|
+
check_fn=check_herm_available,
|
|
16
|
+
emoji="⬡",
|
|
17
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Tool schemas for the eikon plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
EIKON_INSTALL_SCHEMA = {
|
|
6
|
+
"name": "eikon_install",
|
|
7
|
+
"description": (
|
|
8
|
+
"Install a Herm eikon/avatar from the public catalog, a manifest URL, "
|
|
9
|
+
"a git repository, or a local directory. Uses `herm eikon install`; "
|
|
10
|
+
"no separate eikon executable is required."
|
|
11
|
+
),
|
|
12
|
+
"parameters": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"source": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Catalog name, HTTPS manifest/base URL, git URL, or local directory.",
|
|
18
|
+
},
|
|
19
|
+
"name": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "Optional installed name override.",
|
|
22
|
+
},
|
|
23
|
+
"media": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"description": "Whether to fetch source media into the profile. Default true.",
|
|
26
|
+
"default": True,
|
|
27
|
+
},
|
|
28
|
+
"no_source": {
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"description": "Alias for media=false.",
|
|
31
|
+
"default": False,
|
|
32
|
+
},
|
|
33
|
+
"set_active": {
|
|
34
|
+
"type": "boolean",
|
|
35
|
+
"description": "Set the installed eikon as the active Herm avatar. Default true.",
|
|
36
|
+
"default": True,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
"required": ["source"],
|
|
40
|
+
},
|
|
41
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Handlers for the eikon plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _json(data: dict[str, Any]) -> str:
|
|
14
|
+
return json.dumps(data)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _herm_bin() -> str | None:
|
|
18
|
+
override = os.getenv("HERM_EIKON_HERM_BIN", "").strip()
|
|
19
|
+
if override:
|
|
20
|
+
return override
|
|
21
|
+
return shutil.which("herm")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def check_herm_available() -> bool:
|
|
25
|
+
binary = _herm_bin()
|
|
26
|
+
if not binary:
|
|
27
|
+
return False
|
|
28
|
+
if os.path.sep in binary:
|
|
29
|
+
return Path(binary).is_file() and os.access(binary, os.X_OK)
|
|
30
|
+
return shutil.which(binary) is not None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _handle_eikon_install(args: dict[str, Any], **_: Any) -> str:
|
|
34
|
+
source = str(args.get("source") or "").strip()
|
|
35
|
+
if not source:
|
|
36
|
+
return _json({"ok": False, "error": "source is required"})
|
|
37
|
+
|
|
38
|
+
binary = _herm_bin()
|
|
39
|
+
if not binary:
|
|
40
|
+
return _json({"ok": False, "error": "herm executable not found on PATH"})
|
|
41
|
+
|
|
42
|
+
cmd = [binary, "eikon", "install", source, "--json"]
|
|
43
|
+
name = str(args.get("name") or "").strip()
|
|
44
|
+
if name:
|
|
45
|
+
cmd.extend(["--name", name])
|
|
46
|
+
if args.get("media") is False or args.get("no_source") is True:
|
|
47
|
+
cmd.append("--no-source")
|
|
48
|
+
if args.get("set_active") is False:
|
|
49
|
+
cmd.append("--no-use")
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=120, check=False)
|
|
53
|
+
except FileNotFoundError:
|
|
54
|
+
return _json({"ok": False, "error": f"herm executable not found: {binary}"})
|
|
55
|
+
except subprocess.TimeoutExpired:
|
|
56
|
+
return _json({"ok": False, "error": "herm eikon install timed out"})
|
|
57
|
+
|
|
58
|
+
stdout = (proc.stdout or "").strip()
|
|
59
|
+
stderr = (proc.stderr or "").strip()
|
|
60
|
+
if proc.returncode != 0:
|
|
61
|
+
detail = stderr or stdout or f"exit {proc.returncode}"
|
|
62
|
+
return _json({"ok": False, "error": f"herm eikon install failed: {detail}"})
|
|
63
|
+
|
|
64
|
+
line = next((ln for ln in reversed(stdout.splitlines()) if ln.strip()), "")
|
|
65
|
+
try:
|
|
66
|
+
payload = json.loads(line)
|
|
67
|
+
except json.JSONDecodeError:
|
|
68
|
+
return _json({"ok": False, "error": "herm eikon install returned non-JSON output", "output": stdout})
|
|
69
|
+
return _json(payload)
|