lithermes-ai 0.8.4 → 0.8.5

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.
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import argparse
3
4
  import functools
4
5
  from pathlib import Path
5
6
  from typing import Any
@@ -116,16 +117,40 @@ def _pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
116
117
 
117
118
 
118
119
  def _setup_lithermes_cli(parser) -> None:
120
+ try:
121
+ parser.formatter_class = argparse.RawDescriptionHelpFormatter
122
+ except Exception:
123
+ pass
124
+ parser.description = "LitHermes — Hermes-native Litwork toolkit (litgoal runtime, skills, hooks)."
125
+ parser.epilog = (
126
+ "slash commands: /lit /lit-loop /lit-plan /litgoal /review-work /start-work /deep-interview\n"
127
+ "skills: 20 lithermes:* skills — `hermes lithermes status` lists them\n"
128
+ "hooks: pre_llm_call, subagent_stop, transform_llm_output\n"
129
+ "run `hermes lithermes status` for versions + full surface, or `doctor` for health checks"
130
+ )
131
+ parser.add_argument("--version", action="store_true", help="print the LitHermes plugin version")
119
132
  sub = parser.add_subparsers(dest="lh_cmd")
133
+ sub.add_parser("version", help="print the LitHermes plugin version")
134
+ sub.add_parser("status", help="show LitHermes + Hermes versions, hooks, commands, skills")
135
+ sub.add_parser("doctor", help="run LitHermes health checks")
120
136
  goal_parser = sub.add_parser("goal", help="LitHermes litgoal durable runtime")
121
137
  litgoal_cli.setup(goal_parser)
122
138
 
123
139
 
124
140
  def _handle_lithermes_cli(args) -> int:
125
- if getattr(args, "lh_cmd", None) == "goal":
141
+ cmd = getattr(args, "lh_cmd", None)
142
+ if getattr(args, "version", False) or cmd == "version":
143
+ print(core.version_line())
144
+ return 0
145
+ if cmd == "doctor":
146
+ lines, code = core.doctor_report()
147
+ print("\n".join(lines))
148
+ return code
149
+ if cmd == "goal":
126
150
  return litgoal_cli.handle(args)
127
- print("usage: hermes lithermes goal <set|status|criterion|evidence|steer|checkpoint|complete>")
128
- return 1
151
+ # status, or bare `hermes lithermes` the most useful "who am I" answer
152
+ print(core.status_report())
153
+ return 0
129
154
 
130
155
 
131
156
  def _ignited(handler):
@@ -981,3 +981,107 @@ def command_start_work(raw_args: str) -> str | dict[str, str]:
981
981
  "display": display,
982
982
  "agent_message": build_run_agent_message(load_run_state(run_dir)),
983
983
  }
984
+
985
+
986
+ # ---------------------------------------------------------------------------
987
+ # Management / diagnostics surface (hermes lithermes version|status|doctor).
988
+ # Hermes plugins otherwise can't answer "who am I and what version" — these
989
+ # helpers back the CLI subcommands wired in __init__.py.
990
+ # ---------------------------------------------------------------------------
991
+
992
+ PLUGIN_ROOT = Path(__file__).resolve().parent
993
+ # These mirror what register()/register_hook()/litgoal tools wire up in __init__.py.
994
+ # They are hardcoded (not introspected) so `status` works without a live ctx —
995
+ # keep them in sync when adding a hook / slash command / goal tool.
996
+ HOOKS = ("pre_llm_call", "subagent_stop", "transform_llm_output")
997
+ SLASH_COMMANDS = (
998
+ "lit", "lit-loop", "lit-plan", "litgoal", "review-work",
999
+ "start-work", "deep-interview", "litwork-loop", "litwork-plan",
1000
+ )
1001
+ GOAL_TOOLS = (
1002
+ "goal_set", "goal_status", "goal_add_criterion", "goal_evidence",
1003
+ "goal_criterion_status", "goal_steer", "goal_checkpoint", "goal_complete",
1004
+ )
1005
+ _VERSION_RE = re.compile(r"^version:\s*(.+)$", re.MULTILINE)
1006
+
1007
+
1008
+ def plugin_version() -> str:
1009
+ """Read the LitHermes plugin version from the bundled plugin.yaml."""
1010
+ try:
1011
+ m = _VERSION_RE.search((PLUGIN_ROOT / "plugin.yaml").read_text(encoding="utf-8"))
1012
+ return m.group(1).strip().strip("\"'") if m else "unknown"
1013
+ except (OSError, ValueError):
1014
+ return "unknown"
1015
+
1016
+
1017
+ def hermes_host_version() -> str:
1018
+ """Best-effort Hermes host runtime version (unknown outside Hermes)."""
1019
+ try:
1020
+ import hermes_cli
1021
+ return str(getattr(hermes_cli, "__version__", "") or "unknown")
1022
+ except Exception:
1023
+ return "unknown"
1024
+
1025
+
1026
+ def version_line() -> str:
1027
+ return f"lithermes {plugin_version()}"
1028
+
1029
+
1030
+ def _evidence_kinds() -> tuple[str, ...]:
1031
+ try:
1032
+ from .litgoal import model
1033
+ return tuple(model.EVIDENCE_KINDS)
1034
+ except Exception:
1035
+ return ("red", "green", "scenario", "cleanup", "note")
1036
+
1037
+
1038
+ def _skill_names() -> list[str]:
1039
+ skills_dir = PLUGIN_ROOT / "skills"
1040
+ if not skills_dir.is_dir():
1041
+ return []
1042
+ return sorted(d.name for d in skills_dir.iterdir() if (d / "SKILL.md").is_file())
1043
+
1044
+
1045
+ def status_report() -> str:
1046
+ """One-glance health/identity line for `hermes lithermes status`."""
1047
+ skills = _skill_names()
1048
+ return "\n".join([
1049
+ f"LitHermes plugin {plugin_version()} (Hermes host {hermes_host_version()})",
1050
+ f"plugin dir: {PLUGIN_ROOT}",
1051
+ f"hooks ({len(HOOKS)}): {', '.join(HOOKS)}",
1052
+ f"slash commands ({len(SLASH_COMMANDS)}): {', '.join('/' + c for c in SLASH_COMMANDS)}",
1053
+ f"skills ({len(skills)}): {', '.join(skills)}",
1054
+ f"goal tools ({len(GOAL_TOOLS)}): {', '.join(GOAL_TOOLS)}",
1055
+ "litgoal state: .hermes/lithermes/litgoal/ (drive via: hermes lithermes goal status)",
1056
+ f"litgoal evidence kinds: {', '.join(_evidence_kinds())}",
1057
+ ])
1058
+
1059
+
1060
+ def doctor_report() -> tuple[list[str], int]:
1061
+ """Health checks for `hermes lithermes doctor`. Returns (lines, exit_code)."""
1062
+ lines: list[str] = []
1063
+ ok = True
1064
+ ver = plugin_version()
1065
+ if ver != "unknown":
1066
+ lines.append(f"[OK] plugin.yaml readable (version {ver})")
1067
+ else:
1068
+ lines.append("[WARN] plugin.yaml unreadable or missing a version field")
1069
+ ok = False
1070
+ skills = _skill_names()
1071
+ if skills:
1072
+ lines.append(f"[OK] skills bundled: {len(skills)}")
1073
+ else:
1074
+ lines.append("[WARN] no skills found under skills/")
1075
+ ok = False
1076
+ try:
1077
+ from .litgoal import runtime as _rt # noqa: F401
1078
+ lines.append("[OK] litgoal durable runtime importable")
1079
+ except Exception as exc:
1080
+ lines.append(f"[WARN] litgoal runtime import failed: {exc}")
1081
+ ok = False
1082
+ hv = hermes_host_version()
1083
+ if hv != "unknown":
1084
+ lines.append(f"[OK] Hermes host detected (v{hv})")
1085
+ else:
1086
+ lines.append("[NOTE] Hermes host version unknown (running outside Hermes?)")
1087
+ return lines, (0 if ok else 1)
@@ -1,7 +1,7 @@
1
1
  {
2
- "syncedAt": "2026-06-15T16:11:22.931Z",
2
+ "syncedAt": "2026-06-15T16:35:55.443Z",
3
3
  "source": "source-reference",
4
- "sourceHash": "f3b078782aebeb3fea0953852a6e0d93060fe99837c752ac8fd953e15d122ad3",
4
+ "sourceHash": "c93c37881e1f6f5730a1adc6c0e62e4dfab1ca44146eed900b8468448438fe8a",
5
5
  "files": [
6
6
  {
7
7
  "path": "NOTICE.md",
@@ -13,11 +13,11 @@
13
13
  },
14
14
  {
15
15
  "path": "__init__.py",
16
- "sha256": "bb9afee42ee939600aa35324475529c397e612de824bca2c4d64f641281f56fa"
16
+ "sha256": "96b816aee730ea9a5e1fedbc283829240baffddecc37872e4f60bb05f420366c"
17
17
  },
18
18
  {
19
19
  "path": "core.py",
20
- "sha256": "6b9d8b488d5905232d170f78943d2b5f9b9a4bde564e01a816c4fcc45098a7df"
20
+ "sha256": "70ddccfb4cc2fe1a923a5a61244e5cb36ef8ac0f94d34a76703fa6d82dbabf3f"
21
21
  },
22
22
  {
23
23
  "path": "litgoal/__init__.py",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  {
51
51
  "path": "plugin.yaml",
52
- "sha256": "defb9a36febe6f1bf8ca2654e0e93eb236420267c9a2abd52e6869fa47f8fc9c"
52
+ "sha256": "7761c417acfcd614e8d434b3ca11c498f48422a72f5b70f817a59326aca51b60"
53
53
  },
54
54
  {
55
55
  "path": "skills/ai-slop-remover/SKILL.md",
@@ -1,5 +1,5 @@
1
1
  name: lithermes
2
- version: 0.8.4
2
+ version: 0.8.5
3
3
  description: "Hermes-native workflow toolkit: litgoal durable runtime, 5-lane review orchestrator, Litwork commands, skills, and prompt steering."
4
4
  author: "Hermes Agent"
5
5
  kind: standalone
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lithermes-ai",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "npx/bunx installer for the LitHermes Hermes plugin",
5
5
  "license": "MIT",
6
6
  "repository": {