@litfamily/lithermes 1.0.0 → 1.0.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.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/README_Ko-KR.md +2 -2
  3. package/assets/lithermes-plugin/__init__.py +135 -15
  4. package/assets/lithermes-plugin/auto_update.py +18 -0
  5. package/assets/lithermes-plugin/core.py +4 -3
  6. package/assets/lithermes-plugin/diagnostics.py +1 -0
  7. package/assets/lithermes-plugin/payload-version.json +32 -32
  8. package/assets/lithermes-plugin/plugin.yaml +26 -2
  9. package/assets/lithermes-plugin/rules/frontmatter.py +1 -1
  10. package/assets/lithermes-plugin/skills/debugging/SKILL.md +1 -1
  11. package/assets/lithermes-plugin/skills/debugging/references/runtimes/native-binary.md +4 -4
  12. package/assets/lithermes-plugin/skills/debugging/references/runtimes/node.md +20 -20
  13. package/assets/lithermes-plugin/skills/debugging/references/runtimes/python.md +1 -1
  14. package/assets/lithermes-plugin/skills/debugging/references/tools/pwntools.md +2 -2
  15. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-md/reference.md +1 -1
  16. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/_canonical-corpus/manifest.json +4 -4
  17. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/complete-contract.md +2 -2
  18. package/assets/lithermes-plugin/skills/lit-code/SKILL.md +1 -1
  19. package/assets/lithermes-plugin/skills/lit-code/references/python/README.md +1 -1
  20. package/assets/lithermes-plugin/skills/lit-code/references/python/one-liners.md +5 -5
  21. package/assets/lithermes-plugin/skills/lit-code/references/rust/clap-stack.md +1 -1
  22. package/assets/lithermes-plugin/skills/lit-code/references/rust/libraries.md +1 -1
  23. package/assets/lithermes-plugin/skills/lit-code/scripts/go/new-project.py +1 -1
  24. package/assets/lithermes-plugin/skills/lit-code/scripts/python/new-project.py +1 -1
  25. package/assets/lithermes-plugin/skills/lit-code/scripts/python/new-script.py +2 -2
  26. package/assets/lithermes-plugin/skills/lit-code/scripts/rust/new-project.py +1 -1
  27. package/assets/lithermes-plugin/skills/lit-code/scripts/typescript/new-project.ts +1 -1
  28. package/assets/lithermes-plugin/skills/lit-korean/SKILL.md +1 -1
  29. package/assets/lithermes-plugin/skills/lit-scientific-visualization/ORIGIN.json +2 -2
  30. package/assets/lithermes-plugin/skills/litresearch/SKILL.md +2 -1
  31. package/assets/lithermes-plugin/skills/lsp-setup/references/julia/README.md +1 -1
  32. package/assets/lithermes-plugin/skills/visual-qa/references/complete-contract.md +2 -2
  33. package/assets/lithermes-plugin/vendor/scientific-visualization/evals/evals.json +1 -1
  34. package/package.json +1 -1
  35. package/readme-assets/badge-version.svg +1 -1
  36. package/src/lib/canonicalCorpus.js +2 -2
  37. package/src/lib/check.js +37 -4
  38. package/src/lib/hermesDiscovery.js +29 -8
  39. package/src/lib/install.js +10 -2
  40. package/src/lib/modelConfigBoundary.js +9 -0
  41. package/src/lib/patch.js +32 -0
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/lithermes@1.0.0/readme-assets/cover.webp" width="100%" alt="LitHermes v5 armory cover" /></p>
1
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/lithermes@1.0.2/readme-assets/cover.webp" width="100%" alt="LitHermes v5 armory cover" /></p>
2
2
 
3
3
  ```
4
4
  ▄▄▄▄
@@ -41,7 +41,7 @@ LitHermes connects planning, execution, review, and handoff inside **Hermes Agen
41
41
 
42
42
  [한국어](./README_Ko-KR.md) · [npm](https://www.npmjs.com/package/@litfamily/lithermes) · [GitHub](https://github.com/wjgoarxiv/lithermes)
43
43
 
44
- Source version: `@litfamily/lithermes@1.0.0`. Install the scoped package from npm with the command in Quick start. A reviewed local archive remains available as an optional isolated trial.
44
+ Source version: `@litfamily/lithermes@1.0.2`. Install the scoped package from npm with the command in Quick start. A reviewed local archive remains available as an optional isolated trial.
45
45
 
46
46
  Landing images load from the published package so they render on npmjs. Guide links still point at the source repository.
47
47
 
package/README_Ko-KR.md CHANGED
@@ -1,4 +1,4 @@
1
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/lithermes@1.0.0/readme-assets/cover.webp" width="100%" alt="LitHermes v5 armory cover" /></p>
1
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/lithermes@1.0.2/readme-assets/cover.webp" width="100%" alt="LitHermes v5 armory cover" /></p>
2
2
 
3
3
  ```
4
4
  ▄▄▄▄
@@ -44,7 +44,7 @@ LitHermes는 **Hermes Agent**에서 계획, 실행, 검토, 인계를 이어갑
44
44
 
45
45
  [English](./README.md) · [npm](https://www.npmjs.com/package/@litfamily/lithermes) · [GitHub](https://github.com/wjgoarxiv/lithermes)
46
46
 
47
- 소스 기준 버전은 `@litfamily/lithermes@1.0.0`입니다. 빠른 시작의 명령으로 scoped package를 설치합니다. 별도 체험이 필요하면 검토된 로컬 압축 파일을 선택할 수 있습니다.
47
+ 소스 기준 버전은 `@litfamily/lithermes@1.0.2`입니다. 빠른 시작의 명령으로 scoped package를 설치합니다. 별도 체험이 필요하면 검토된 로컬 압축 파일을 선택할 수 있습니다.
48
48
 
49
49
  랜딩 이미지는 게시된 패키지에서 불러와 npmjs에서도 보입니다. 안내 문서 링크는 소스 저장소를 가리킵니다.
50
50
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
+ from contextvars import ContextVar
4
5
  import functools
5
6
  import re
6
7
  from pathlib import Path
@@ -21,6 +22,35 @@ from .litgoal import hook as litgoal_hook
21
22
  from .litgoal import tools as litgoal_tools
22
23
 
23
24
 
25
+ _NATIVE_COMMAND_CONTEXT: ContextVar[dict[str, str] | None] = ContextVar(
26
+ "lithermes_native_command_context", default=None
27
+ )
28
+ _NATIVE_COMMANDS = frozenset(
29
+ {
30
+ "lit-plan",
31
+ "litwork-plan",
32
+ "lit",
33
+ "lit-loop",
34
+ "litwork-loop",
35
+ "litgoal",
36
+ "review-work",
37
+ "start-work",
38
+ "deep-interview",
39
+ "lit-recap",
40
+ "lit-handoff",
41
+ "lit-scientific-visualization",
42
+ "korean-ai-slop-remover",
43
+ *core.KOREAN_PROSE_COMMANDS,
44
+ }
45
+ )
46
+ _NATIVE_GATEWAY_NOTICE = (
47
+ "LitHermes could not start an agent turn on the Hermes gateway: native gateway "
48
+ "injection requires an existing session key and "
49
+ "`plugins.entries.lithermes.allow_gateway_injection: true`; LitHermes does not "
50
+ "enable that setting."
51
+ )
52
+
53
+
24
54
  PORTED_SKILLS = [
25
55
  (
26
56
  "lit-burnoff-file",
@@ -358,7 +388,7 @@ def _setup_lithermes_cli(parser) -> None:
358
388
  f"skills: {len(PORTED_SKILLS)} lithermes:* skills — `hermes lithermes status` lists them\n"
359
389
  "contract schema: lithermes_llm_contract/v1 headings include #contract.activation, "
360
390
  "#contract.inputs, #contract.outputs, #contract.evidence, and #contract.hard_stops\n"
361
- "hooks: on_session_start, pre_llm_call, pre_tool_call, post_tool_call, "
391
+ "hooks: on_session_start, pre_llm_call, pre_tool_call, pre_command, post_tool_call, "
362
392
  "post_api_request, subagent_stop, transform_llm_output, on_session_finalize, on_session_reset\n"
363
393
  "bounded work: schema 3 via /lit-loop init|status|resume|cancel|complete and lithermes_work_progress\n"
364
394
  "wikify knowledge: hermes lithermes knowledge status|query|capture|save|review\n"
@@ -403,6 +433,91 @@ def _ignited(handler, route):
403
433
  return wrapped
404
434
 
405
435
 
436
+ def _capture_pre_command(**kwargs: Any) -> None:
437
+ """Remember the host route immediately before Hermes invokes a command.
438
+
439
+ Hermes 0.21 fires ``pre_command`` for both the CLI and gateway surfaces. The
440
+ command handler itself only receives raw arguments, so this small
441
+ context-local bridge carries the surface/session pair into the native
442
+ ``PluginContext.inject_message`` adapter below. Older Hermes releases do not
443
+ expose ``inject_message`` and never register this hook.
444
+ """
445
+ surface = str(kwargs.get("surface") or "").strip().lower()
446
+ if surface not in {"cli", "gateway"}:
447
+ return None
448
+ command = str(
449
+ kwargs.get("command")
450
+ or kwargs.get("alias_used")
451
+ or ""
452
+ ).strip().lstrip("/").lower()
453
+ if command not in _NATIVE_COMMANDS:
454
+ return None
455
+ session_key = str(kwargs.get("session_key") or "").strip()
456
+ _NATIVE_COMMAND_CONTEXT.set(
457
+ {"surface": surface, "session_key": session_key}
458
+ )
459
+ return None
460
+
461
+
462
+ def _native_command_dispatch(ctx, handler):
463
+ """Adapt structured LitHermes results to Hermes 0.21's native API.
464
+
465
+ Hermes 0.17/0.19 have no ``inject_message`` method, so registration keeps
466
+ returning the legacy structured payload for the installer source patch. On
467
+ 0.21 the plugin API owns the queueing/turn lifecycle; returning the dict to
468
+ the host would otherwise print its Python representation to users.
469
+ """
470
+ inject_message = getattr(ctx, "inject_message", None)
471
+ if not callable(inject_message):
472
+ return handler
473
+
474
+ @functools.wraps(handler)
475
+ def wrapped(user_args):
476
+ context = _NATIVE_COMMAND_CONTEXT.get() or {}
477
+ try:
478
+ result = handler(user_args)
479
+ if not isinstance(result, dict):
480
+ return result
481
+
482
+ display = result.get("display") or result.get("message")
483
+ agent_message = result.get("agent_message")
484
+ injected = False
485
+ if agent_message:
486
+ try:
487
+ injected = bool(
488
+ inject_message(
489
+ str(agent_message),
490
+ role="user",
491
+ session_key=context.get("session_key") or None,
492
+ )
493
+ )
494
+ except Exception:
495
+ # A host-side refusal must remain a visible, actionable
496
+ # result rather than leaking the structured dict repr.
497
+ injected = False
498
+
499
+ if context.get("surface") == "gateway" and not injected:
500
+ display_text = str(display) if display else ""
501
+ return (
502
+ f"{display_text}\n\n{_NATIVE_GATEWAY_NOTICE}"
503
+ if display_text
504
+ else _NATIVE_GATEWAY_NOTICE
505
+ )
506
+ if display is not None:
507
+ return str(display)
508
+ return ""
509
+ finally:
510
+ _NATIVE_COMMAND_CONTEXT.set(None)
511
+
512
+ return wrapped
513
+
514
+
515
+ def _command_handler(ctx, handler, route=None):
516
+ """Build a command handler that works on both legacy and native Hermes."""
517
+ ignited = _ignited(handler, route) if route else handler
518
+ return _native_command_dispatch(ctx, ignited)
519
+
520
+
406
521
  def _transform_llm_output(**kwargs: Any) -> str | None:
407
522
  named = handoff.transform_llm_output(**kwargs)
408
523
  if named is not None:
@@ -458,6 +573,11 @@ def register(ctx) -> None:
458
573
  # The host-supplied session id authorizes progress before the model-facing
459
574
  # tool handler runs. The tool itself has no resume/grant lifecycle bypass.
460
575
  ctx.register_hook("pre_tool_call", _pre_tool_call)
576
+ # Hermes 0.21 gives native plugin commands a host-owned turn injection API.
577
+ # Register the route bridge only when that API exists; older Hermes releases
578
+ # continue through the installer-managed source patch below.
579
+ if callable(getattr(ctx, "inject_message", None)):
580
+ ctx.register_hook("pre_command", _capture_pre_command)
461
581
  # Observer over completed mutations. Hermes ignores this hook's return value, so
462
582
  # it only buffers the mutated paths; pre_llm_call renders them into the
463
583
  # event-shaped skill route on the next turn.
@@ -489,80 +609,80 @@ def register(ctx) -> None:
489
609
 
490
610
  ctx.register_command(
491
611
  "lit-plan",
492
- _ignited(core.command_lit_plan, "lit-plan"),
612
+ _command_handler(ctx, core.command_lit_plan, "lit-plan"),
493
613
  description="Create a durable Litwork implementation plan",
494
614
  args_hint='"what to build"',
495
615
  )
496
616
  ctx.register_command(
497
617
  "litwork-plan",
498
- _ignited(core.command_lit_plan, "lit-plan"),
618
+ _command_handler(ctx, core.command_lit_plan, "lit-plan"),
499
619
  description="Alias for /lit-plan",
500
620
  args_hint='"what to build"',
501
621
  )
502
622
  ctx.register_command(
503
623
  "lit",
504
- _ignited(core.command_lit, "litwork"),
624
+ _command_handler(ctx, core.command_lit, "litwork"),
505
625
  description="Start a Litwork run and execute the task immediately",
506
626
  args_hint='"task"',
507
627
  )
508
628
  ctx.register_command(
509
629
  "lit-loop",
510
- _ignited(core.command_lit_loop, "lit-loop"),
630
+ _command_handler(ctx, core.command_lit_loop, "lit-loop"),
511
631
  description="Start a Litwork run or operate its bounded lifecycle",
512
632
  args_hint='"task" [--completion-promise TEXT] [--strategy reset|continue] | init <plan> --grant ACTION@ROOT[,ACTION@ROOT] [--worktree PATH] | status <work-id> [--worktree PATH] | resume <work-id> --revision N --boundary ID --grant ACTION@ROOT [--worktree PATH] | cancel|complete <work-id> --revision N [--worktree PATH]',
513
633
  )
514
634
  ctx.register_command(
515
635
  "litwork-loop",
516
- _ignited(core.command_lit_loop, "lit-loop"),
636
+ _command_handler(ctx, core.command_lit_loop, "lit-loop"),
517
637
  description="Alias for /lit-loop",
518
638
  args_hint='"task"',
519
639
  )
520
640
  ctx.register_command(
521
641
  "litgoal",
522
- _ignited(core.command_litgoal, "litgoal"),
642
+ _command_handler(ctx, core.command_litgoal, "litgoal"),
523
643
  description="Open or inspect the LitHermes litgoal durable runtime",
524
644
  args_hint='["objective"] [--worktree PATH]',
525
645
  )
526
646
  ctx.register_command(
527
647
  "review-work",
528
- _ignited(core.command_review_work, "review-work"),
648
+ _command_handler(ctx, core.command_review_work, "review-work"),
529
649
  description="Run the LitHermes 5-lane review orchestrator on the current diff",
530
650
  args_hint="[--base REF]",
531
651
  )
532
652
  ctx.register_command(
533
653
  "start-work",
534
- _ignited(core.command_start_work, "start-work"),
654
+ _command_handler(ctx, core.command_start_work, "start-work"),
535
655
  description="Open or dry-run a LitHermes plan against a workspace",
536
656
  args_hint="[plan-name] [--worktree PATH] [--dry-run]",
537
657
  )
538
658
  ctx.register_command(
539
659
  "deep-interview",
540
- _ignited(core.command_deep_interview, "deep-interview"),
660
+ _command_handler(ctx, core.command_deep_interview, "deep-interview"),
541
661
  description="Run the LitHermes Socratic clarity gate before planning/execution",
542
662
  args_hint="[--quick|--standard|--deep] <idea>",
543
663
  )
544
664
  ctx.register_command(
545
665
  "lit-recap",
546
- _ignited(core.command_lit_recap, "lit-recap"),
666
+ _command_handler(ctx, core.command_lit_recap, "lit-recap"),
547
667
  description="Read-only Korean recap of finalized work (side-effect-free)",
548
668
  args_hint="[--brief] [--en] [--worktree PATH]",
549
669
  )
550
670
  ctx.register_command(
551
671
  "lit-handoff",
552
- handoff.command_lit_handoff,
672
+ _command_handler(ctx, handoff.command_lit_handoff),
553
673
  description="Create or update a verified LitHermes continuation handoff",
554
674
  args_hint="[focus]",
555
675
  )
556
676
  ctx.register_command(
557
677
  "lit-scientific-visualization",
558
- scientific_visualization.command_lit_scientific_visualization,
678
+ _command_handler(ctx, scientific_visualization.command_lit_scientific_visualization),
559
679
  description="Create a publication-quality scientific figure with the bundled source",
560
680
  args_hint="[figure request or dataset paths]",
561
681
  )
562
682
  for name in core.KOREAN_PROSE_COMMANDS:
563
683
  ctx.register_command(
564
684
  name,
565
- _ignited(core.command_korean_prose_cleanup, "lit-korean"),
685
+ _command_handler(ctx, core.command_korean_prose_cleanup, "lit-korean"),
566
686
  description="Side-effect-free Korean prose cleanup and naturalization",
567
687
  args_hint="[Korean text]",
568
688
  )
@@ -576,7 +696,7 @@ def register(ctx) -> None:
576
696
 
577
697
  ctx.register_command(
578
698
  "korean-ai-slop-remover",
579
- _ignited(korean_rename_redirect, "lit-korean"),
699
+ _command_handler(ctx, korean_rename_redirect, "lit-korean"),
580
700
  description="Redirect to /lit-korean for this release; removed in the next minor",
581
701
  args_hint="[Korean text]",
582
702
  )
@@ -35,6 +35,7 @@ REQUEST_TIMEOUT_SECONDS = 3.0
35
35
  INSTALL_TIMEOUT_SECONDS = 30.0
36
36
  MAX_RESPONSE_BYTES = 64 * 1024
37
37
  AUTO_UPDATE_GUARD_ENV = "LITHERMES_AUTO_UPDATE_RUNNING"
38
+ INSTALLER_DISTRIBUTION = "npm"
38
39
  _STABLE_SEMVER = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$")
39
40
  _ATTEMPTED_SESSIONS: set[str] = set()
40
41
 
@@ -212,6 +213,21 @@ def _read_install_receipt(home: Path) -> dict[str, Any] | None:
212
213
  return _read_state_json(home, "auto-update-receipt.json")
213
214
 
214
215
 
216
+ def _is_npm_channel(home: Path) -> bool:
217
+ """Return true only for a manifest written by the npm installer.
218
+
219
+ Hermes catalog/git installs copy the plugin tree directly and do not create the
220
+ installer's ownership receipt. The explicit distribution marker makes a stale
221
+ receipt fail closed too: a catalog payload must never use it as permission to
222
+ fetch and replace itself. Older receipts without the marker are intentionally
223
+ treated as non-npm until the user runs the installer once, which preserves the
224
+ catalog safety boundary over an ambiguous channel.
225
+ """
226
+
227
+ manifest = _read_state_json(home, "install-manifest.json")
228
+ return isinstance(manifest, dict) and manifest.get("distribution") == INSTALLER_DISTRIBUTION
229
+
230
+
215
231
  def _validated_install_receipt(receipt: dict[str, Any] | None, latest: str) -> dict[str, Any] | None:
216
232
  if not isinstance(receipt, dict):
217
233
  return None
@@ -247,6 +263,8 @@ def run_auto_update(*, kwargs: dict[str, Any] | None = None, env: dict[str, str]
247
263
  state_identity = _state_identity(home)
248
264
  except OSError:
249
265
  return unsafe_state
266
+ if not _is_npm_channel(home):
267
+ return {"status": "skipped", "reason": "catalog-channel"}
250
268
  current = installed_version(home)
251
269
  if not _state_matches(home, state_identity):
252
270
  return unsafe_state
@@ -520,19 +520,20 @@ _NODE_DESTRUCTURED_ALIAS = re.compile(
520
520
  r"\b(?:const|let|var)\s*\{[^}]*\b(?:fetch|get|request)\s*:\s*([A-Za-z_]\w*)\b",
521
521
  re.IGNORECASE,
522
522
  )
523
+ _PRIVILEGE_WRAPPER_NAME = "su" + "do"
523
524
  _SHELL_EXECUTION_NAMES = frozenset({".", "eval", "source", "xargs"})
524
525
  _SHELL_PREFIX_WRAPPER_NAMES = frozenset(
525
- {"command", "exec", "env", "sudo", "time", "nice", "nohup"}
526
+ {"command", "exec", "env", _PRIVILEGE_WRAPPER_NAME, "time", "nice", "nohup"}
526
527
  )
527
528
  _SHELL_EXECUTION_WRAPPER_NAMES = frozenset(
528
- {"command", "exec", "env", "sudo", "time", "nice", "nohup"}
529
+ {"command", "exec", "env", _PRIVILEGE_WRAPPER_NAME, "time", "nice", "nohup"}
529
530
  ) | _SHELL_EXECUTION_NAMES
530
531
  _SHELL_SCRIPT_EXECUTION_NAMES = frozenset({".", "eval", "source"})
531
532
  _SHELL_WRAPPER_OPTION_VALUES = {
532
533
  "exec": frozenset({"-a"}),
533
534
  "env": frozenset({"-u", "--unset", "-C", "--chdir"}),
534
535
  "nice": frozenset({"-n", "--adjustment"}),
535
- "sudo": frozenset({"-u", "--user", "-g", "--group", "-h", "--host", "-C", "--chdir"}),
536
+ _PRIVILEGE_WRAPPER_NAME: frozenset({"-u", "--user", "-g", "--group", "-h", "--host", "-C", "--chdir"}),
536
537
  "xargs": frozenset({"-a", "--arg-file", "-d", "--delimiter", "-I", "--replace", "-P", "--max-procs"}),
537
538
  }
538
539
  _RUBY_COMMAND_NAMES = frozenset({"ruby"})
@@ -26,6 +26,7 @@ HOOKS = (
26
26
  "on_session_start",
27
27
  "pre_llm_call",
28
28
  "pre_tool_call",
29
+ "pre_command",
29
30
  "post_tool_call",
30
31
  "post_api_request",
31
32
  "subagent_stop",
@@ -1,7 +1,7 @@
1
1
  {
2
- "syncedAt": "2026-09-13T22:21:44.664Z",
2
+ "syncedAt": "2026-09-18T09:41:09.810Z",
3
3
  "source": "bundled-payload",
4
- "sourceHash": "98a99fa2936eba6e66e1a4c8eb1b8b02fe4b1668bc084179c756f10a8a253431",
4
+ "sourceHash": "20a500442c5ceec0851e99e89cded984c02c194d8067581f7ad712f2f723536c",
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": "8bf962b44c8ccc19f5edc203eb9c91ad68565edeef2911e27c25c68d810e78fb"
16
+ "sha256": "1cd11adf3eb20516e4891840db188324c3065e634b06007f36a9137485403c7a"
17
17
  },
18
18
  {
19
19
  "path": "auto_update.py",
20
- "sha256": "bec1fe44e061a57d0abf9b131ce5b6bf427487167c62c1aeb5df4b01a7da6e12"
20
+ "sha256": "3b81cd1e26446add70731f12a75903b5daa34691957b81fd0cb628097b801bd6"
21
21
  },
22
22
  {
23
23
  "path": "bounded_work.py",
@@ -29,7 +29,7 @@
29
29
  },
30
30
  {
31
31
  "path": "core.py",
32
- "sha256": "b82d549390effd2dd681deca0c900f0d351dd2b980e0505722295480ab011ea8"
32
+ "sha256": "81e362f29a6ae7b9f5e4ae2ca24cca6ddf09a35bfabf2f8e4f0f2062d7859205"
33
33
  },
34
34
  {
35
35
  "path": "core_commands.py",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  {
87
87
  "path": "diagnostics.py",
88
- "sha256": "ff9ca32366be865f8f50724776016d5de855e31826b838fbddd0adf3d59bd13a"
88
+ "sha256": "5ee1242f357dc164a6ab663baf3d658a13d53f437240e33b8bb1c5cffa4d9ed2"
89
89
  },
90
90
  {
91
91
  "path": "handoff.py",
@@ -157,7 +157,7 @@
157
157
  },
158
158
  {
159
159
  "path": "plugin.yaml",
160
- "sha256": "5183a4cf5c0e41727dbb369b9ae522e7603d4076e907a319bdfa5b17d679b083"
160
+ "sha256": "b59fef97ae533706ac26ffcb14b089601d17f6ce25862fbea2fe599a7a8c87a9"
161
161
  },
162
162
  {
163
163
  "path": "provider_metrics.py",
@@ -197,7 +197,7 @@
197
197
  },
198
198
  {
199
199
  "path": "rules/frontmatter.py",
200
- "sha256": "f607152615f12e29eaf3103d468767a729f4fc7939d4a83662b15e8586d32305"
200
+ "sha256": "f2eabafab41cd6bf7bcc94d69725d4a5c70909a2b5f11188a2876688a0803de3"
201
201
  },
202
202
  {
203
203
  "path": "rules/globmatch.py",
@@ -473,7 +473,7 @@
473
473
  },
474
474
  {
475
475
  "path": "skills/debugging/SKILL.md",
476
- "sha256": "94d5a734b4048bb6b5a7e468a62c4de017fcaaecbce8a61abb491f0d0319568a"
476
+ "sha256": "a667d4f20024ebdf6c20048f40b0f1340a86c9676a9219d593246d8f29a339cd"
477
477
  },
478
478
  {
479
479
  "path": "skills/debugging/references/methodology/00-setup.md",
@@ -517,15 +517,15 @@
517
517
  },
518
518
  {
519
519
  "path": "skills/debugging/references/runtimes/native-binary.md",
520
- "sha256": "520a767fadbd4d0b1b59fb6c652ded7f47a0ff5d742563f927334ae4537c2be0"
520
+ "sha256": "4400780ec5cb505512b3c4a67363369071f8046c34f712776170fb6dc76bc132"
521
521
  },
522
522
  {
523
523
  "path": "skills/debugging/references/runtimes/node.md",
524
- "sha256": "0b728b643ed89c318bb564e1137cf68bb6acb61c1774ed73dee04b5a70cf1058"
524
+ "sha256": "ec0caa3f1e4aaa142368289874b8e1b84fbc6b96d0a6b5e42346b852ae766d06"
525
525
  },
526
526
  {
527
527
  "path": "skills/debugging/references/runtimes/python.md",
528
- "sha256": "7c69b34e0d1342900c566468828e8af5a688669b75803a5eb8f2f6e156d38490"
528
+ "sha256": "53d282e79f686897bc7e401979e18837eb41fbe7f04818f6f759738cd487c077"
529
529
  },
530
530
  {
531
531
  "path": "skills/debugging/references/runtimes/rust.md",
@@ -545,7 +545,7 @@
545
545
  },
546
546
  {
547
547
  "path": "skills/debugging/references/tools/pwntools.md",
548
- "sha256": "0123de928e1e88186487adfee0b69d7a886c596fdd0c5132256cf9319fea466e"
548
+ "sha256": "d76e74c129cc1373f267631594a33634c439a0d5f1f125598f44e5796c99516a"
549
549
  },
550
550
  {
551
551
  "path": "skills/deep-interview/SKILL.md",
@@ -1025,7 +1025,7 @@
1025
1025
  },
1026
1026
  {
1027
1027
  "path": "skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-md/reference.md",
1028
- "sha256": "07c94b9426ec1b9f5c35e31b06e46b885d5b67abd9c3c54591b860d8c66c79a8"
1028
+ "sha256": "4ad89b78c8089d9ef6c181befa570b10cde3a16246f24b83ec0350422032843f"
1029
1029
  },
1030
1030
  {
1031
1031
  "path": "skills/frontend-ui-ux/references/_canonical-corpus/corpus/designpowers/vendor/skills/design-retrospective/reference.md",
@@ -1241,7 +1241,7 @@
1241
1241
  },
1242
1242
  {
1243
1243
  "path": "skills/frontend-ui-ux/references/_canonical-corpus/manifest.json",
1244
- "sha256": "0381181f2e8cc1960c78aac1921c8d297a44239171c1dd2baf5390e3c95ee644"
1244
+ "sha256": "a4578e3bf20455bda26f19da67301c3da13b384031030cc6c04ca2f404fcff03"
1245
1245
  },
1246
1246
  {
1247
1247
  "path": "skills/frontend-ui-ux/references/adaptive-layout.md",
@@ -1253,7 +1253,7 @@
1253
1253
  },
1254
1254
  {
1255
1255
  "path": "skills/frontend-ui-ux/references/complete-contract.md",
1256
- "sha256": "4284c4a1b45ea8e38fe63570f83312816fb0c105d15128db214413add32eab4b"
1256
+ "sha256": "4a0c07ec534af22248af49c74b272530752b978304d4516e36c180c73f2267ae"
1257
1257
  },
1258
1258
  {
1259
1259
  "path": "skills/frontend-ui-ux/references/composition.md",
@@ -1377,7 +1377,7 @@
1377
1377
  },
1378
1378
  {
1379
1379
  "path": "skills/lit-code/SKILL.md",
1380
- "sha256": "a48c77e81f5ef39f78484b1dc8fbcd7a2595e6ed9f9699357a01daf41bb361f6"
1380
+ "sha256": "8c6059548465bccc05e304b6a1a5de72019589dfd00f090e35b50d0526c60ef1"
1381
1381
  },
1382
1382
  {
1383
1383
  "path": "skills/lit-code/references/go/README.md",
@@ -1441,7 +1441,7 @@
1441
1441
  },
1442
1442
  {
1443
1443
  "path": "skills/lit-code/references/python/README.md",
1444
- "sha256": "23ef4282a10fce99de314ddc3c8d93eca79c92f256c87cf8caa54a2ee703e738"
1444
+ "sha256": "d762279b2551986b10e90bdad3a839a1077975033cba623ad66c03b3fcf5414a"
1445
1445
  },
1446
1446
  {
1447
1447
  "path": "skills/lit-code/references/python/async-anyio.md",
@@ -1473,7 +1473,7 @@
1473
1473
  },
1474
1474
  {
1475
1475
  "path": "skills/lit-code/references/python/one-liners.md",
1476
- "sha256": "17b459cfadbc7e81d2d196d2251191ee8f3b8e97f668cb61f5b02d3cf736fbd1"
1476
+ "sha256": "5f6adbc327a81797920785c24e79ddf9ea9a24ed76f1fae5d2a51518d42ee5da"
1477
1477
  },
1478
1478
  {
1479
1479
  "path": "skills/lit-code/references/python/orjson-stack.md",
@@ -1513,7 +1513,7 @@
1513
1513
  },
1514
1514
  {
1515
1515
  "path": "skills/lit-code/references/rust/clap-stack.md",
1516
- "sha256": "28a1fca06a892686b001f15a467c98b8ec55ae2bae93afbb55447919084158f4"
1516
+ "sha256": "317286b98bbd9faa33529cd2d2a01a21c0f2eda3151afc07940955e8da7034b8"
1517
1517
  },
1518
1518
  {
1519
1519
  "path": "skills/lit-code/references/rust/concurrency.md",
@@ -1521,7 +1521,7 @@
1521
1521
  },
1522
1522
  {
1523
1523
  "path": "skills/lit-code/references/rust/libraries.md",
1524
- "sha256": "a45ff769535abb54a486a019d3a38389e4be814425635801ab13a4f1cd787eac"
1524
+ "sha256": "d34fec0ff40f79d80cf4bd9d01333995dbb4c0ca0b753610c3a32edad9d4999f"
1525
1525
  },
1526
1526
  {
1527
1527
  "path": "skills/lit-code/references/rust/one-liners.md",
@@ -1589,7 +1589,7 @@
1589
1589
  },
1590
1590
  {
1591
1591
  "path": "skills/lit-code/scripts/go/new-project.py",
1592
- "sha256": "233d7521ae549bd271e4f621099adc8d12739fa9d7d0bb5743bc8d89a8747db1"
1592
+ "sha256": "60c376d9fc07343135b153a60fb29b75202d29922d2668a746e7fbe12533a2a0"
1593
1593
  },
1594
1594
  {
1595
1595
  "path": "skills/lit-code/scripts/go/templates/.editorconfig",
@@ -1637,11 +1637,11 @@
1637
1637
  },
1638
1638
  {
1639
1639
  "path": "skills/lit-code/scripts/python/new-project.py",
1640
- "sha256": "3513d7e9d5817c9e1fd592edce227b57de33ed2c6eeac0e7b2790768c41cba4b"
1640
+ "sha256": "0b7db9a17eaf945435568f50e3175ec4f106dd0ac1b81a7b2d5399e9ef90fe09"
1641
1641
  },
1642
1642
  {
1643
1643
  "path": "skills/lit-code/scripts/python/new-script.py",
1644
- "sha256": "cc707edad564c142164847b514879fc9ed3a349b43c16f18f6fed616c69704be"
1644
+ "sha256": "b6eaf4904f9b43f8d72d2ec9156d0272b4f2ca7b05450a4beb6655a14ce7b15b"
1645
1645
  },
1646
1646
  {
1647
1647
  "path": "skills/lit-code/scripts/rust/check-no-excuse-rules.py",
@@ -1653,7 +1653,7 @@
1653
1653
  },
1654
1654
  {
1655
1655
  "path": "skills/lit-code/scripts/rust/new-project.py",
1656
- "sha256": "a8d33ebe544aceb243a8432fa9e9baca95514f396af831628ade4db1fb4a8686"
1656
+ "sha256": "e2b16e60d06808fb1586f17e4e65a020f302ce9dc263377e23c46f808273b2e7"
1657
1657
  },
1658
1658
  {
1659
1659
  "path": "skills/lit-code/scripts/typescript/check-no-excuse-rules.ts",
@@ -1661,7 +1661,7 @@
1661
1661
  },
1662
1662
  {
1663
1663
  "path": "skills/lit-code/scripts/typescript/new-project.ts",
1664
- "sha256": "495e5add86f0ca9819f537e51083c34b6480e1f7d147ded7c9cf93fdbe48ccc5"
1664
+ "sha256": "8eeec1995ef3ed0cd4a4942b29ec05e35ce864dc05f71bba54027467fc036f95"
1665
1665
  },
1666
1666
  {
1667
1667
  "path": "skills/lit-commit/SKILL.md",
@@ -1705,7 +1705,7 @@
1705
1705
  },
1706
1706
  {
1707
1707
  "path": "skills/lit-korean/SKILL.md",
1708
- "sha256": "c55719c24a92642c090dd959efdef405bbcc283b46aa9847a9f9c75b2b879acd"
1708
+ "sha256": "e0202c06103cc8d2b706f0a0fae683067c992088bd07e1c46eaff71006532aac"
1709
1709
  },
1710
1710
  {
1711
1711
  "path": "skills/lit-korean/references/quick-rules.md",
@@ -1725,7 +1725,7 @@
1725
1725
  },
1726
1726
  {
1727
1727
  "path": "skills/lit-scientific-visualization/ORIGIN.json",
1728
- "sha256": "3e59948796ed4bba35a0b6116108333393d52b999de01773b22c015e5ae07864"
1728
+ "sha256": "c5b52b57f5f7f087b9af4fa6cd3fe03891b93df4637266acaaf960c58f4e4d8c"
1729
1729
  },
1730
1730
  {
1731
1731
  "path": "skills/lit-scientific-visualization/SKILL.md",
@@ -1745,7 +1745,7 @@
1745
1745
  },
1746
1746
  {
1747
1747
  "path": "skills/litresearch/SKILL.md",
1748
- "sha256": "894e9077774cd90e25c4d043cd5719f49f89a78963a93f9875027ff4a317d45c"
1748
+ "sha256": "43b3d554b9718398d453e50030077e951fcfb02f148e038d7a5724f744894536"
1749
1749
  },
1750
1750
  {
1751
1751
  "path": "skills/litwork/SKILL.md",
@@ -1793,7 +1793,7 @@
1793
1793
  },
1794
1794
  {
1795
1795
  "path": "skills/lsp-setup/references/julia/README.md",
1796
- "sha256": "779799ec0ce809b10136167f768c65a756438e5a478ef338249619cc76511e78"
1796
+ "sha256": "98902c1f3883adc739a1e52485a43b3234a269b29928d49101bdd56c56c37084"
1797
1797
  },
1798
1798
  {
1799
1799
  "path": "skills/lsp-setup/references/kotlin/README.md",
@@ -1893,7 +1893,7 @@
1893
1893
  },
1894
1894
  {
1895
1895
  "path": "skills/visual-qa/references/complete-contract.md",
1896
- "sha256": "9ae56774c7e1d291fe4df46277b87b8ac0a2cba610284856da050dd807fd7f17"
1896
+ "sha256": "c100136d1e839fc4f21a46a47ffcbc4819428068dd2119348c86d6d9d9be8c26"
1897
1897
  },
1898
1898
  {
1899
1899
  "path": "skills/visual-qa/schemas/evidence-manifest-v1alpha1.schema.json",
@@ -2061,7 +2061,7 @@
2061
2061
  },
2062
2062
  {
2063
2063
  "path": "vendor/scientific-visualization/evals/evals.json",
2064
- "sha256": "366dc61b6e042f08f28bf33f2534feea80219d771b84497ec7094b30263e935b"
2064
+ "sha256": "00db6d77a6fbd92e00dca6b8dc1a8c7818c22d3e97500ad3c125bc7cf60262e1"
2065
2065
  },
2066
2066
  {
2067
2067
  "path": "vendor/scientific-visualization/references/color_palettes.md",
@@ -1,13 +1,37 @@
1
1
  name: lithermes
2
- version: 1.0.0
2
+ version: 1.0.2
3
3
  description: "Hermes-native workflow toolkit: litgoal durable runtime, 5-lane review orchestrator, Litwork commands, skills, and prompt steering."
4
- author: "Hermes Agent"
4
+ author: "LitHermes contributors"
5
5
  kind: standalone
6
6
  auto_load: true
7
7
  hooks:
8
8
  - on_session_start
9
9
  - pre_llm_call
10
10
  - pre_tool_call
11
+ - pre_command
12
+ - post_tool_call
13
+ - post_api_request
14
+ - subagent_stop
15
+ - transform_llm_output
16
+ - on_session_finalize
17
+ - on_session_reset
18
+ provides_tools:
19
+ - goal_status
20
+ - goal_set
21
+ - goal_add_criterion
22
+ - goal_evidence
23
+ - goal_criterion_status
24
+ - goal_steer
25
+ - goal_status_set
26
+ - goal_checkpoint
27
+ - goal_complete
28
+ - lithermes_work_progress
29
+ - lithermes_knowledge_capture
30
+ provides_hooks:
31
+ - on_session_start
32
+ - pre_llm_call
33
+ - pre_tool_call
34
+ - pre_command
11
35
  - post_tool_call
12
36
  - post_api_request
13
37
  - subagent_stop