cluxion-agentplugin-preprocessing 0.3.22__tar.gz → 0.3.24__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.
Files changed (105) hide show
  1. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/Docs/README.md +4 -2
  2. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/PKG-INFO +33 -1
  3. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/README.md +32 -0
  4. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/claude/skills/preprocess/SKILL.md +4 -1
  5. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/install-and-operations.md +1 -0
  6. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/pyproject.toml +1 -1
  7. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/cli.py +43 -3
  8. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/guard_watch.py +18 -0
  9. cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/hermes_deliver_patch.py +373 -0
  10. cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/patches/hermes-deliver-agent.patch +89 -0
  11. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/plugin.py +2 -0
  12. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/plugin.yaml +1 -1
  13. cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/slash_commands.py +121 -0
  14. cluxion_agentplugin_preprocessing-0.3.24/tests/test_hermes_deliver_patch.py +21 -0
  15. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_plugin.py +17 -0
  16. cluxion_agentplugin_preprocessing-0.3.24/tests/test_slash_commands.py +8 -0
  17. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/.github/profile/README.md +0 -0
  18. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/.gitignore +0 -0
  19. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/LICENSE +0 -0
  20. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/claude/.claude-plugin/plugin.json +0 -0
  21. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/codex/config-snippet.toml +0 -0
  22. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/README.md +0 -0
  23. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/architecture.md +0 -0
  24. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/harness-logic.md +0 -0
  25. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/honesty-preprocessing.md +0 -0
  26. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/security.md +0 -0
  27. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/Cargo.lock +0 -0
  28. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/Cargo.toml +0 -0
  29. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/pyproject.toml +0 -0
  30. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/context.rs +0 -0
  31. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/dispatch.rs +0 -0
  32. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/guard.rs +0 -0
  33. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/lib.rs +0 -0
  34. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/main.rs +0 -0
  35. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/queue.rs +0 -0
  36. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/types.rs +0 -0
  37. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/uv.lock +0 -0
  38. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/__init__.py +0 -0
  39. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/__init__.py +0 -0
  40. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/catalog.json +0 -0
  41. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/framework.py +0 -0
  42. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/probes.py +0 -0
  43. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/hermes_config.py +0 -0
  44. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/runner.py +0 -0
  45. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/schemas.py +0 -0
  46. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/__init__.py +0 -0
  47. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/__main__.py +0 -0
  48. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/__init__.py +0 -0
  49. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/contract.py +0 -0
  50. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/grok_build.py +0 -0
  51. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/hermes.py +0 -0
  52. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/spec.py +0 -0
  53. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/bootstrap.py +0 -0
  54. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/cli.py +0 -0
  55. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/__init__.py +0 -0
  56. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/clarification.py +0 -0
  57. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/context_compress.py +0 -0
  58. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/dispatch_store.py +0 -0
  59. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/harness.py +0 -0
  60. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/hybrid_forget.py +0 -0
  61. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/intent.py +0 -0
  62. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/ledger.py +0 -0
  63. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/ledger_codec.py +0 -0
  64. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/llm_compress.py +0 -0
  65. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/loop_auto.py +0 -0
  66. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/plan_codec.py +0 -0
  67. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/preprocess.py +0 -0
  68. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/types.py +0 -0
  69. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/work_queue.py +0 -0
  70. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/guard_daemon_host.py +0 -0
  71. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/__init__.py +0 -0
  72. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/supervisor.py +0 -0
  73. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/vllm_mlx.py +0 -0
  74. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/__init__.py +0 -0
  75. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/guard_bridge.py +0 -0
  76. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/py_queue.py +0 -0
  77. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/queue_bridge.py +0 -0
  78. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/rust_bridge.py +0 -0
  79. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/web/__init__.py +0 -0
  80. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/web/browser_bridge.py +0 -0
  81. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_auto_compress_middleware.py +0 -0
  82. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_bin_resolution.py +0 -0
  83. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_browser_bridge.py +0 -0
  84. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_clarification.py +0 -0
  85. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_cluxion_runtime_spine.py +0 -0
  86. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_context_compress.py +0 -0
  87. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_context_compress_llm_forget.py +0 -0
  88. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_contract.py +0 -0
  89. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_dispatch_store.py +0 -0
  90. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_estimate_tokens.py +0 -0
  91. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_guard.py +0 -0
  92. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_guard_daemon_host.py +0 -0
  93. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_ledger.py +0 -0
  94. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_loop_auto.py +0 -0
  95. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_py_queue_concurrency.py +0 -0
  96. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_queue_backends.py +0 -0
  97. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_runtime_adapter_cli.py +0 -0
  98. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_rust_queue.py +0 -0
  99. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_supervisor.py +0 -0
  100. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_bootstrap.py +0 -0
  101. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_doctor.py +0 -0
  102. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_guard_watch.py +0 -0
  103. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_hermes_config.py +0 -0
  104. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_packaging_policy.py +0 -0
  105. {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_runner.py +0 -0
@@ -17,7 +17,7 @@
17
17
 
18
18
  1. 사용자 요청 수신 → `cluxion_plan` (또는 `cluxion-runtime plan`)
19
19
  2. `clarification.required`이면 사용자에게 질문, 작업 보류
20
- 3. `queued` 모드면 `cluxion_queue_next` → segment 처리 → `cluxion_queue_record` `cluxion_queue_brief`
20
+ 3. `queued` 모드: 수동이면 `cluxion_queue_next` → → `cluxion_queue_brief`. Hermes 긴 작업은 `/loopauto` 또는 `loop_auto: true`(기본)로 자동 드레인.
21
21
  4. `answer_policy.required_checks`를 지키며 응답
22
22
  5. (선택) `cluxion_queue_brief` 결과를 ForgetForge에 저장: `forgetforge import-brief --source preprocessing`
23
23
 
@@ -37,7 +37,9 @@ cluxion-preprocess enable # Hermes
37
37
  |------|------|
38
38
  | [architecture.md](architecture.md) | 패키지 구조, 데이터 흐름, host 경계 |
39
39
  | [design.md](design.md) | 정직함, 명확화, 성능 |
40
- | [installation.md](installation.md) | 설치, Hermes 활성화, Rust 큐 |
40
+ | [installation.md](installation.md) | 설치, Hermes 활성화, 슬래시, Rust 큐 |
41
+ | [tools.md](tools.md) | 도구·슬래시·loopAuto·queued workflow |
42
+ | 통합 가이드 | MacBot `Docs/cluxion-plugins-guide.md` §2-A (5종 슬래시 전체) |
41
43
  | [tools.md](tools.md) | 도구, preprocessing mode, queue |
42
44
  | [agent-surfaces.md](agent-surfaces.md) | Hermes / Claude / Codex / Grok |
43
45
  | [rust-architecture.md](rust-architecture.md) | Rust 메인 · Python adapter |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cluxion-agentplugin-preprocessing
3
- Version: 0.3.22
3
+ Version: 0.3.24
4
4
  Summary: Universal agent plugin for Cluxion preprocessing, honesty contracts, clarification, Rust work queue, and resource-aware harness handoff.
5
5
  Project-URL: Homepage, https://github.com/cluxion/cluxion-Agentplugin-preprocessing
6
6
  Project-URL: Repository, https://github.com/cluxion/cluxion-Agentplugin-preprocessing
@@ -84,6 +84,22 @@ cluxion-preprocess doctor --json # 구조화 출력
84
84
 
85
85
  Hermes 안에서는 `cluxion_doctor` 도구로도 노출됩니다.
86
86
 
87
+ ## Hermes 슬래시 커맨드 (0.3.23+)
88
+
89
+ `/` 입력 시 🔌로 자동완성됩니다.
90
+
91
+ | 슬래시 | 용도 |
92
+ |---|---|
93
+ | `/loopauto <prompt>` | plan + 자동 큐 드레인 (`/loopAuto` 지시어와 동일) |
94
+ | `/cluxion-doctor` | doctor (CLI `cluxion-preprocess doctor`와 동일) |
95
+
96
+ ```
97
+ /loopauto 4000줄 요구사항을 순서대로 구현하고 각 항목 증거를 남겨줘
98
+ /cluxion-doctor
99
+ ```
100
+
101
+ 비활성: `export CLUXION_LOOP_AUTO=0` · 상세: `Docs/cluxion-plugins-guide.md` §5-A (통합 가이드)
102
+
87
103
  ## 문제 해결
88
104
 
89
105
  | 증상 | 해결 |
@@ -152,6 +168,22 @@ cluxion-preprocess doctor --json # structured output
152
168
 
153
169
  Also exposed inside Hermes as the `cluxion_doctor` tool.
154
170
 
171
+ ## Hermes slash commands (0.3.23+)
172
+
173
+ Type `/` to see plugin commands with a 🔌 badge.
174
+
175
+ | Slash | Purpose |
176
+ |---|---|
177
+ | `/loopauto <prompt>` | Plan + autonomous queue drain (same as `/loopAuto` directive) |
178
+ | `/cluxion-doctor` | Run doctor (same as `cluxion-preprocess doctor`) |
179
+
180
+ ```
181
+ /loopauto implement every REQ line and record evidence
182
+ /cluxion-doctor
183
+ ```
184
+
185
+ Disable auto-loop: `export CLUXION_LOOP_AUTO=0`.
186
+
155
187
  ## Troubleshooting
156
188
 
157
189
  | Problem | Fix |
@@ -52,6 +52,22 @@ cluxion-preprocess doctor --json # 구조화 출력
52
52
 
53
53
  Hermes 안에서는 `cluxion_doctor` 도구로도 노출됩니다.
54
54
 
55
+ ## Hermes 슬래시 커맨드 (0.3.23+)
56
+
57
+ `/` 입력 시 🔌로 자동완성됩니다.
58
+
59
+ | 슬래시 | 용도 |
60
+ |---|---|
61
+ | `/loopauto <prompt>` | plan + 자동 큐 드레인 (`/loopAuto` 지시어와 동일) |
62
+ | `/cluxion-doctor` | doctor (CLI `cluxion-preprocess doctor`와 동일) |
63
+
64
+ ```
65
+ /loopauto 4000줄 요구사항을 순서대로 구현하고 각 항목 증거를 남겨줘
66
+ /cluxion-doctor
67
+ ```
68
+
69
+ 비활성: `export CLUXION_LOOP_AUTO=0` · 상세: `Docs/cluxion-plugins-guide.md` §5-A (통합 가이드)
70
+
55
71
  ## 문제 해결
56
72
 
57
73
  | 증상 | 해결 |
@@ -120,6 +136,22 @@ cluxion-preprocess doctor --json # structured output
120
136
 
121
137
  Also exposed inside Hermes as the `cluxion_doctor` tool.
122
138
 
139
+ ## Hermes slash commands (0.3.23+)
140
+
141
+ Type `/` to see plugin commands with a 🔌 badge.
142
+
143
+ | Slash | Purpose |
144
+ |---|---|
145
+ | `/loopauto <prompt>` | Plan + autonomous queue drain (same as `/loopAuto` directive) |
146
+ | `/cluxion-doctor` | Run doctor (same as `cluxion-preprocess doctor`) |
147
+
148
+ ```
149
+ /loopauto implement every REQ line and record evidence
150
+ /cluxion-doctor
151
+ ```
152
+
153
+ Disable auto-loop: `export CLUXION_LOOP_AUTO=0`.
154
+
123
155
  ## Troubleshooting
124
156
 
125
157
  | Problem | Fix |
@@ -17,11 +17,14 @@ stdin: `{"prompt": "<user request>", "cwd": "<workspace>"}`
17
17
 
18
18
  Hermes에서는 `cluxion_plan` 도구를 동일 목적으로 사용합니다.
19
19
 
20
+ Hermes 슬래시 (0.3.23+): `/loopauto <prompt>` — plan + 자동 큐 드레인. `/cluxion-doctor` — 점검.
21
+
20
22
  ## 규칙
21
23
 
22
24
  1. `clarification.required`이 true이면 사용자에게 질문하고 작업을 시작하지 말 것.
23
25
  2. context가 부족하면 모른다고 말할 것 — 사실을 지어내지 말 것.
24
- 3. `queued` 모드: `cluxion_queue_next` → segment 처리 → `cluxion_queue_record` → `cluxion_queue_brief`.
26
+ 3. `queued` 모드: 수동이면 `cluxion_queue_next` → segment 처리 → `cluxion_queue_record` → `cluxion_queue_brief`.
27
+ 긴 작업은 Hermes에서 `/loopauto` 또는 plan `loop_auto: true`(기본 on)로 자동 드레인.
25
28
  4. 세션 맥락 보존이 필요하면 brief를 ForgetForge에 넘길 것: `forgetforge import-brief --source preprocessing --brief "<cluxion_queue_brief output>"` (또는 Hermes `forgetforge_import_brief`).
26
29
  5. `answer_policy.required_checks`를 응답 전에 따를 것.
27
30
  6. 플러그인이 대신 completion을 생성하지 않음 — **당신**이 계약에 맞게 응답할 것.
@@ -13,6 +13,7 @@ cluxion-preprocess enable # Hermes
13
13
  ## 연결된 AI 연동
14
14
 
15
15
  - Hermes: `cluxion_*` 도구 (plugin enable 후)
16
+ - Hermes 슬래시 (0.3.23+): `/loopauto`, `/cluxion-doctor` — `/` 자동완성
16
17
  - Claude: `adapters/claude/skills/preprocess/SKILL.md`
17
18
  - Codex: `adapters/codex/config-snippet.toml`
18
19
  - 공통: `cluxion-runtime plan --surface <hermes|claude|codex|grok_build>`
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cluxion-agentplugin-preprocessing"
7
- version = "0.3.22"
7
+ version = "0.3.24"
8
8
  description = "Universal agent plugin for Cluxion preprocessing, honesty contracts, clarification, Rust work queue, and resource-aware harness handoff."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -9,7 +9,7 @@ import sys
9
9
  from pathlib import Path
10
10
  from typing import TYPE_CHECKING
11
11
 
12
- from cluxion_agentplugin_preprocessing import __version__, hermes_config, runner
12
+ from cluxion_agentplugin_preprocessing import __version__, hermes_config, hermes_deliver_patch, runner
13
13
  from cluxion_agentplugin_preprocessing.doctor import (
14
14
  render_json,
15
15
  render_text,
@@ -39,6 +39,8 @@ def main(argv: Sequence[str] | None = None) -> int:
39
39
  return _hermes_config(args)
40
40
  if args.command == "doctor":
41
41
  return _doctor(args)
42
+ if args.command == "hermes-patch":
43
+ return _hermes_patch(args)
42
44
  parser.print_help(sys.stderr)
43
45
  return 2
44
46
 
@@ -83,6 +85,21 @@ def _parser() -> argparse.ArgumentParser:
83
85
  doctor = subparsers.add_parser("doctor", help="Run embedded health checks")
84
86
  doctor.add_argument("--json", action="store_true")
85
87
  doctor.add_argument("--verbose", action="store_true")
88
+ patch = subparsers.add_parser(
89
+ "hermes-patch",
90
+ help="Apply or verify Hermes deliver=agent patch (/supercoder routing)",
91
+ )
92
+ patch.add_argument(
93
+ "--status",
94
+ action="store_true",
95
+ help="Only report patch status (default: ensure applied)",
96
+ )
97
+ patch.add_argument("--dry-run", action="store_true")
98
+ patch.add_argument(
99
+ "--hermes-root",
100
+ default=None,
101
+ help="Hermes agent source root (default: auto-detect ~/.hermes/hermes-agent)",
102
+ )
86
103
  return parser
87
104
 
88
105
 
@@ -117,8 +134,10 @@ def _status(args: argparse.Namespace) -> int:
117
134
 
118
135
  def _enable(args: argparse.Namespace) -> int:
119
136
  result = hermes_config.enable_plugin(args.home, dry_run=bool(args.dry_run))
120
- print(json.dumps({"ok": True, **result.to_dict()}, ensure_ascii=False, sort_keys=True))
121
- return 0
137
+ patch = _ensure_hermes_patch(dry_run=bool(args.dry_run))
138
+ payload = {"ok": True, **result.to_dict(), "hermes_patch": patch.to_dict()}
139
+ print(json.dumps(payload, ensure_ascii=False, sort_keys=True))
140
+ return 0 if patch.status in {"applied", "no_hermes"} or args.dry_run else 1
122
141
 
123
142
 
124
143
  def _disable(args: argparse.Namespace) -> int:
@@ -142,6 +161,27 @@ def _hermes_config(args: argparse.Namespace) -> int:
142
161
  return 0 if result.ok else 1
143
162
 
144
163
 
164
+ def _hermes_root_arg(args: argparse.Namespace) -> Path | None:
165
+ raw = getattr(args, "hermes_root", None)
166
+ return Path(raw).expanduser() if raw else None
167
+
168
+
169
+ def _ensure_hermes_patch(*, dry_run: bool, hermes_root: Path | None = None) -> hermes_deliver_patch.PatchResult:
170
+ if dry_run:
171
+ return hermes_deliver_patch.patch_status(hermes_root)
172
+ return hermes_deliver_patch.ensure_applied(hermes_root=hermes_root)
173
+
174
+
175
+ def _hermes_patch(args: argparse.Namespace) -> int:
176
+ root = _hermes_root_arg(args)
177
+ if args.status:
178
+ result = hermes_deliver_patch.patch_status(root)
179
+ else:
180
+ result = hermes_deliver_patch.ensure_applied(hermes_root=root, dry_run=bool(args.dry_run))
181
+ print(json.dumps({"ok": result.status == "applied", **result.to_dict()}, ensure_ascii=False, sort_keys=True))
182
+ return 0 if result.status == "applied" else 1
183
+
184
+
145
185
  def _doctor(args: argparse.Namespace) -> int:
146
186
  pkg = "cluxion_agentplugin_preprocessing.doctor"
147
187
  catalog_path = Path(str(importlib.resources.files(pkg).joinpath("catalog.json")))
@@ -38,6 +38,7 @@ def on_session_start(**_: Any) -> None:
38
38
  Startup is idempotent: an already-running daemon is success. Hook failures
39
39
  are logged as one concise stderr warning and never propagated to the host.
40
40
  """
41
+ _maybe_apply_hermes_deliver_patch()
41
42
  if not _autostart_enabled():
42
43
  return
43
44
  try:
@@ -51,6 +52,23 @@ def on_session_start(**_: Any) -> None:
51
52
  _warn(f"cluxion guard autostart failed: {reason}")
52
53
 
53
54
 
55
+ def _maybe_apply_hermes_deliver_patch() -> None:
56
+ """Best-effort Hermes deliver=agent patch (``CLUXION_HERMES_PATCH_AUTOFIX``, default on)."""
57
+ try:
58
+ from cluxion_agentplugin_preprocessing import hermes_deliver_patch
59
+
60
+ if not hermes_deliver_patch.autostart_enabled():
61
+ return
62
+ status = hermes_deliver_patch.patch_status()
63
+ if status.status == "applied":
64
+ return
65
+ result = hermes_deliver_patch.ensure_applied()
66
+ if result.status != "applied" and result.status != "no_hermes":
67
+ _warn(f"cluxion hermes deliver patch: {result.detail}")
68
+ except Exception as exc:
69
+ _warn(f"cluxion hermes deliver patch failed: {exc}")
70
+
71
+
54
72
  def post_tool_call(**_: Any) -> None:
55
73
  """Run a throttled guard watch after tool calls.
56
74
 
@@ -0,0 +1,373 @@
1
+ """Apply and verify Hermes core support for plugin slash ``deliver=agent``."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import tempfile
9
+ from dataclasses import dataclass
10
+ from datetime import UTC, datetime
11
+ from importlib import resources
12
+ from pathlib import Path
13
+ from typing import Literal
14
+
15
+ PATCH_RESOURCE = "patches/hermes-deliver-agent.patch"
16
+ BRANCH_NAME = "cluxion/plugin-deliver-agent"
17
+
18
+ Status = Literal["applied", "missing", "partial", "no_hermes"]
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class PatchResult:
23
+ hermes_root: Path
24
+ status: Status
25
+ applied: bool
26
+ changed: bool
27
+ method: str
28
+ detail: str
29
+
30
+ def to_dict(self) -> dict[str, object]:
31
+ return {
32
+ "hermes_root": str(self.hermes_root),
33
+ "status": self.status,
34
+ "applied": self.applied,
35
+ "changed": self.changed,
36
+ "method": self.method,
37
+ "detail": self.detail,
38
+ }
39
+
40
+
41
+ def resolve_hermes_agent_root(home: str | os.PathLike[str] | None = None) -> Path | None:
42
+ """Best-effort Hermes agent source tree (contains ``hermes_cli/``)."""
43
+ candidates: list[Path] = []
44
+ env_root = os.environ.get("HERMES_AGENT_ROOT", "").strip()
45
+ if env_root:
46
+ candidates.append(Path(env_root).expanduser())
47
+ if home is not None:
48
+ candidates.append(Path(home).expanduser() / "hermes-agent")
49
+ hermes_home = Path(os.environ.get("HERMES_HOME", "")).expanduser() if os.environ.get("HERMES_HOME") else Path.home() / ".hermes"
50
+ candidates.append(hermes_home / "hermes-agent")
51
+
52
+ hermes_bin = shutil.which("hermes")
53
+ if hermes_bin:
54
+ try:
55
+ resolved = Path(hermes_bin).resolve()
56
+ for parent in resolved.parents:
57
+ if (parent / "hermes_cli" / "plugins.py").is_file():
58
+ candidates.append(parent)
59
+ break
60
+ except OSError:
61
+ pass
62
+
63
+ seen: set[Path] = set()
64
+ for root in candidates:
65
+ if root in seen:
66
+ continue
67
+ seen.add(root)
68
+ if (root / "hermes_cli" / "plugins.py").is_file():
69
+ return root
70
+ return None
71
+
72
+
73
+ def patch_status(hermes_root: Path | None = None) -> PatchResult:
74
+ root = hermes_root or resolve_hermes_agent_root()
75
+ if root is None:
76
+ return PatchResult(Path(), "no_hermes", False, False, "none", "hermes-agent tree not found")
77
+
78
+ checks = {
79
+ "plugins": _plugins_applied(root),
80
+ "cli": _cli_applied(root),
81
+ "gateway_dispatch": _gateway_dispatch_applied(root),
82
+ "gateway_slash_exec": _gateway_slash_exec_applied(root),
83
+ }
84
+ ok_count = sum(1 for v in checks.values() if v)
85
+ if ok_count == len(checks):
86
+ return PatchResult(root, "applied", True, False, "verify", "all markers present")
87
+ if ok_count == 0:
88
+ return PatchResult(root, "missing", False, False, "verify", f"missing: {checks}")
89
+ return PatchResult(root, "partial", False, False, "verify", f"partial: {checks}")
90
+
91
+
92
+ def ensure_applied(
93
+ *,
94
+ hermes_root: Path | None = None,
95
+ dry_run: bool = False,
96
+ ) -> PatchResult:
97
+ """Idempotently apply deliver=agent support to the local Hermes checkout."""
98
+ current = patch_status(hermes_root)
99
+ if current.status == "no_hermes":
100
+ return current
101
+ if current.status == "applied":
102
+ return PatchResult(current.hermes_root, "applied", True, False, "noop", "already applied")
103
+
104
+ if dry_run:
105
+ return PatchResult(
106
+ current.hermes_root,
107
+ current.status,
108
+ False,
109
+ False,
110
+ "dry_run",
111
+ f"would apply ({current.detail})",
112
+ )
113
+
114
+ for method, result in (
115
+ ("git_branch", _apply_via_git_branch(current.hermes_root)),
116
+ ("git_apply", _apply_via_git_patch(current.hermes_root)),
117
+ ("inline", _apply_inline(current.hermes_root)),
118
+ ):
119
+ if result:
120
+ after = patch_status(current.hermes_root)
121
+ if after.status == "applied":
122
+ return PatchResult(
123
+ current.hermes_root,
124
+ "applied",
125
+ True,
126
+ True,
127
+ method,
128
+ "patch applied successfully",
129
+ )
130
+
131
+ after = patch_status(current.hermes_root)
132
+ return PatchResult(
133
+ current.hermes_root,
134
+ after.status,
135
+ after.status == "applied",
136
+ False,
137
+ "failed",
138
+ after.detail,
139
+ )
140
+
141
+
142
+ def _plugins_applied(root: Path) -> bool:
143
+ text = (root / "hermes_cli" / "plugins.py").read_text(encoding="utf-8")
144
+ return 'deliver: str = "output"' in text and '"deliver": deliver_mode' in text
145
+
146
+
147
+ def _cli_applied(root: Path) -> bool:
148
+ text = (root / "cli.py").read_text(encoding="utf-8")
149
+ return 'entry.get("deliver") == "agent"' in text and "_pending_input.put(str(result))" in text
150
+
151
+
152
+ def _gateway_dispatch_applied(root: Path) -> bool:
153
+ text = (root / "tui_gateway" / "server.py").read_text(encoding="utf-8")
154
+ return '"type": "send"' in text and 'entry.get("deliver") == "agent"' in text
155
+
156
+
157
+ def _gateway_slash_exec_applied(root: Path) -> bool:
158
+ text = (root / "tui_gateway" / "server.py").read_text(encoding="utf-8")
159
+ return "agent-deliver command: use command.dispatch" in text
160
+
161
+
162
+ def _apply_via_git_branch(root: Path) -> bool:
163
+ if not (root / ".git").is_dir():
164
+ return False
165
+ try:
166
+ subprocess.run(
167
+ ["git", "rev-parse", "--verify", BRANCH_NAME],
168
+ cwd=root,
169
+ check=True,
170
+ capture_output=True,
171
+ text=True,
172
+ )
173
+ subprocess.run(["git", "checkout", BRANCH_NAME], cwd=root, check=True, capture_output=True, text=True)
174
+ return True
175
+ except (subprocess.CalledProcessError, OSError):
176
+ return False
177
+
178
+
179
+ def _apply_via_git_patch(root: Path) -> bool:
180
+ if not (root / ".git").is_dir():
181
+ return False
182
+ try:
183
+ patch_bytes = resources.files("cluxion_agentplugin_preprocessing").joinpath(PATCH_RESOURCE).read_bytes()
184
+ except (FileNotFoundError, ModuleNotFoundError):
185
+ return False
186
+ with tempfile.NamedTemporaryFile("wb", suffix=".patch", delete=False) as handle:
187
+ handle.write(patch_bytes)
188
+ patch_path = Path(handle.name)
189
+ try:
190
+ subprocess.run(
191
+ ["git", "apply", "--check", str(patch_path)],
192
+ cwd=root,
193
+ check=True,
194
+ capture_output=True,
195
+ text=True,
196
+ )
197
+ subprocess.run(["git", "apply", str(patch_path)], cwd=root, check=True, capture_output=True, text=True)
198
+ return True
199
+ except (subprocess.CalledProcessError, OSError):
200
+ return False
201
+ finally:
202
+ patch_path.unlink(missing_ok=True)
203
+
204
+
205
+ def _apply_inline(root: Path) -> bool:
206
+ try:
207
+ changed = False
208
+ changed |= _patch_plugins_py(root)
209
+ changed |= _patch_cli_py(root)
210
+ changed |= _patch_tui_gateway(root)
211
+ return changed
212
+ except OSError:
213
+ return False
214
+
215
+
216
+ def _backup(path: Path) -> None:
217
+ if not path.exists():
218
+ return
219
+ stamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ")
220
+ shutil.copy2(path, path.with_name(f"{path.name}.bak-cluxion-{stamp}"))
221
+
222
+
223
+ def _patch_plugins_py(root: Path) -> bool:
224
+ path = root / "hermes_cli" / "plugins.py"
225
+ text = path.read_text(encoding="utf-8")
226
+ if _plugins_applied(root):
227
+ return False
228
+ if 'args_hint: str = "",\n ) -> None:' not in text:
229
+ return False
230
+ old = (
231
+ " self._manager._plugin_commands[clean] = {\n"
232
+ ' "handler": handler,\n'
233
+ ' "description": description or "Plugin command",\n'
234
+ ' "plugin": self.manifest.name,\n'
235
+ ' "args_hint": (args_hint or "").strip(),\n'
236
+ " }"
237
+ )
238
+ new = (
239
+ " deliver_mode = (deliver or \"output\").strip().lower()\n"
240
+ ' if deliver_mode not in {"output", "agent"}:\n'
241
+ ' deliver_mode = "output"\n'
242
+ " self._manager._plugin_commands[clean] = {\n"
243
+ ' "handler": handler,\n'
244
+ ' "description": description or "Plugin command",\n'
245
+ ' "plugin": self.manifest.name,\n'
246
+ ' "args_hint": (args_hint or "").strip(),\n'
247
+ ' "deliver": deliver_mode,\n'
248
+ " }"
249
+ )
250
+ if old not in text:
251
+ return False
252
+ _backup(path)
253
+ text = text.replace(
254
+ 'args_hint: str = "",\n ) -> None:',
255
+ 'args_hint: str = "",\n deliver: str = "output",\n ) -> None:',
256
+ 1,
257
+ )
258
+ text = text.replace(old, new, 1)
259
+ path.write_text(text, encoding="utf-8")
260
+ return True
261
+
262
+
263
+ def _patch_cli_py(root: Path) -> bool:
264
+ path = root / "cli.py"
265
+ text = path.read_text(encoding="utf-8")
266
+ if _cli_applied(root):
267
+ return False
268
+ old = (
269
+ " try:\n"
270
+ " result = resolve_plugin_command_result(\n"
271
+ " plugin_handler(user_args)\n"
272
+ " )\n"
273
+ " if result:\n"
274
+ " _cprint(str(result))"
275
+ )
276
+ new = (
277
+ " try:\n"
278
+ " from hermes_cli.plugins import get_plugin_commands\n"
279
+ "\n"
280
+ ' cmd_key = base_cmd.lstrip("/")\n'
281
+ " entry = get_plugin_commands().get(cmd_key, {})\n"
282
+ " result = resolve_plugin_command_result(\n"
283
+ " plugin_handler(user_args)\n"
284
+ " )\n"
285
+ " if (\n"
286
+ ' entry.get("deliver") == "agent"\n'
287
+ " and user_args.strip()\n"
288
+ " and result\n"
289
+ ' and hasattr(self, "_pending_input")\n'
290
+ " ):\n"
291
+ " _cprint(\n"
292
+ ' f"\\n⚡ /{cmd_key} → agent "\n'
293
+ ' f"({len(str(result))} chars)"\n'
294
+ " )\n"
295
+ ' self._pending_input.put(str(result))\n'
296
+ " elif result:\n"
297
+ " _cprint(str(result))"
298
+ )
299
+ if old not in text:
300
+ return False
301
+ _backup(path)
302
+ path.write_text(text.replace(old, new, 1), encoding="utf-8")
303
+ return True
304
+
305
+
306
+ def _patch_tui_gateway(root: Path) -> bool:
307
+ path = root / "tui_gateway" / "server.py"
308
+ text = path.read_text(encoding="utf-8")
309
+ changed = False
310
+ if not _gateway_dispatch_applied(root):
311
+ old = (
312
+ " if handler:\n"
313
+ " result = resolve_plugin_command_result(handler(arg))\n"
314
+ ' return _ok(rid, {"type": "plugin", "output": str(result or "")})'
315
+ )
316
+ new = (
317
+ " if handler:\n"
318
+ " from hermes_cli.plugins import get_plugin_commands\n"
319
+ "\n"
320
+ " result = resolve_plugin_command_result(handler(arg))\n"
321
+ " entry = get_plugin_commands().get(name, {})\n"
322
+ ' if entry.get("deliver") == "agent" and arg.strip() and result:\n'
323
+ ' return _ok(rid, {"type": "send", "message": str(result)})\n'
324
+ ' return _ok(rid, {"type": "plugin", "output": str(result or "")})'
325
+ )
326
+ if old in text:
327
+ _backup(path)
328
+ text = text.replace(old, new, 1)
329
+ changed = True
330
+ if not _gateway_slash_exec_applied(root):
331
+ old = (
332
+ " if plugin_handler and resolve_plugin_command_result:\n"
333
+ " try:\n"
334
+ " result = resolve_plugin_command_result(plugin_handler(_cmd_arg))\n"
335
+ ' return _ok(rid, {"output": str(result or "(no output)")})'
336
+ )
337
+ new = (
338
+ " if plugin_handler and resolve_plugin_command_result:\n"
339
+ " try:\n"
340
+ " from hermes_cli.plugins import get_plugin_commands\n"
341
+ "\n"
342
+ " entry = get_plugin_commands().get(_cmd_base, {})\n"
343
+ ' if entry.get("deliver") == "agent":\n'
344
+ " return _err(\n"
345
+ " rid,\n"
346
+ " 4018,\n"
347
+ ' f"agent-deliver command: use command.dispatch for /{_cmd_base}",\n'
348
+ " )\n"
349
+ " result = resolve_plugin_command_result(plugin_handler(_cmd_arg))\n"
350
+ ' return _ok(rid, {"output": str(result or "(no output)")})'
351
+ )
352
+ if old in text:
353
+ if not changed:
354
+ _backup(path)
355
+ text = text.replace(old, new, 1)
356
+ changed = True
357
+ if changed:
358
+ path.write_text(text, encoding="utf-8")
359
+ return changed
360
+
361
+
362
+ def autostart_enabled() -> bool:
363
+ value = os.environ.get("CLUXION_HERMES_PATCH_AUTOFIX", "1").strip().lower()
364
+ return value not in {"0", "false", "no", "off"}
365
+
366
+
367
+ __all__ = [
368
+ "PatchResult",
369
+ "autostart_enabled",
370
+ "ensure_applied",
371
+ "patch_status",
372
+ "resolve_hermes_agent_root",
373
+ ]