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.
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/Docs/README.md +4 -2
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/PKG-INFO +33 -1
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/README.md +32 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/claude/skills/preprocess/SKILL.md +4 -1
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/install-and-operations.md +1 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/pyproject.toml +1 -1
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/cli.py +43 -3
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/guard_watch.py +18 -0
- cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/hermes_deliver_patch.py +373 -0
- cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/patches/hermes-deliver-agent.patch +89 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/plugin.py +2 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/plugin.yaml +1 -1
- cluxion_agentplugin_preprocessing-0.3.24/src/cluxion_agentplugin_preprocessing/slash_commands.py +121 -0
- cluxion_agentplugin_preprocessing-0.3.24/tests/test_hermes_deliver_patch.py +21 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_plugin.py +17 -0
- cluxion_agentplugin_preprocessing-0.3.24/tests/test_slash_commands.py +8 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/.github/profile/README.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/.gitignore +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/LICENSE +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/claude/.claude-plugin/plugin.json +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/adapters/codex/config-snippet.toml +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/README.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/architecture.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/harness-logic.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/honesty-preprocessing.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/cluxion-Docs/security.md +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/Cargo.lock +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/Cargo.toml +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/pyproject.toml +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/context.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/dispatch.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/guard.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/lib.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/main.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/queue.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/src/types.rs +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/rust/cluxion_queue/uv.lock +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/catalog.json +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/framework.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/doctor/probes.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/hermes_config.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/runner.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_agentplugin_preprocessing/schemas.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/__main__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/contract.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/grok_build.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/hermes.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/adapters/spec.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/bootstrap.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/cli.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/clarification.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/context_compress.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/dispatch_store.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/harness.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/hybrid_forget.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/intent.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/ledger.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/ledger_codec.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/llm_compress.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/loop_auto.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/plan_codec.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/preprocess.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/types.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/core/work_queue.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/guard_daemon_host.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/supervisor.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/models/vllm_mlx.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/guard_bridge.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/py_queue.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/queue_bridge.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/resources/rust_bridge.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/web/__init__.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/src/cluxion_runtime/web/browser_bridge.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_auto_compress_middleware.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_bin_resolution.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_browser_bridge.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_clarification.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_cluxion_runtime_spine.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_context_compress.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_context_compress_llm_forget.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_contract.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_dispatch_store.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_estimate_tokens.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_guard.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_guard_daemon_host.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_ledger.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_loop_auto.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_py_queue_concurrency.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_queue_backends.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_runtime_adapter_cli.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_rust_queue.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/runtime/test_supervisor.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_bootstrap.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_doctor.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_guard_watch.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_hermes_config.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_packaging_policy.py +0 -0
- {cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/tests/test_runner.py +0 -0
{cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/Docs/README.md
RENAMED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
1. 사용자 요청 수신 → `cluxion_plan` (또는 `cluxion-runtime plan`)
|
|
19
19
|
2. `clarification.required`이면 사용자에게 질문, 작업 보류
|
|
20
|
-
3. `queued`
|
|
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 |
|
{cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cluxion-agentplugin-preprocessing
|
|
3
|
-
Version: 0.3.
|
|
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 |
|
{cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/README.md
RENAMED
|
@@ -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>`
|
{cluxion_agentplugin_preprocessing-0.3.22 → cluxion_agentplugin_preprocessing-0.3.24}/pyproject.toml
RENAMED
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cluxion-agentplugin-preprocessing"
|
|
7
|
-
version = "0.3.
|
|
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
|
-
|
|
121
|
-
|
|
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
|
+
]
|