claude-smart 0.2.46 → 0.2.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +19 -11
- package/bin/claude-smart.js +290 -68
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +11 -10
- package/plugin/dashboard/app/layout.tsx +20 -0
- package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +36 -2
- package/plugin/dashboard/package-lock.json +61 -390
- package/plugin/dashboard/package.json +2 -2
- package/plugin/opencode/dist/server.mjs +76 -2
- package/plugin/opencode/server.mts +79 -2
- package/plugin/pyproject.toml +6 -2
- package/plugin/scripts/smart-install.sh +7 -1
- package/plugin/src/claude_smart/cli.py +210 -22
- package/plugin/src/claude_smart/context_format.py +9 -9
- package/plugin/src/claude_smart/cs_cite.py +66 -19
- package/plugin/uv.lock +5 -5
- package/plugin/vendor/reflexio/.env.example +7 -0
- package/plugin/vendor/reflexio/README.md +3 -3
- package/plugin/vendor/reflexio/pyproject.toml +2 -1
- package/plugin/vendor/reflexio/reflexio/README.md +11 -6
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +1 -1
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +2 -2
- package/plugin/vendor/reflexio/reflexio/cli/utils.py +44 -1
- package/plugin/vendor/reflexio/reflexio/client/client.py +97 -0
- package/plugin/vendor/reflexio/reflexio/lib/_agent_playbook.py +8 -0
- package/plugin/vendor/reflexio/reflexio/lib/_base.py +15 -0
- package/plugin/vendor/reflexio/reflexio/lib/_config.py +23 -18
- package/plugin/vendor/reflexio/reflexio/lib/_generation.py +9 -8
- package/plugin/vendor/reflexio/reflexio/lib/_interactions.py +16 -1
- package/plugin/vendor/reflexio/reflexio/lib/_profiles.py +27 -16
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +27 -5
- package/plugin/vendor/reflexio/reflexio/lib/_user_playbook.py +9 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/__init__.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/enums.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/governance.py +117 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +45 -3
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +37 -0
- package/plugin/vendor/reflexio/reflexio/server/README.md +38 -9
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +21 -2
- package/plugin/vendor/reflexio/reflexio/server/api.py +274 -3267
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +4 -3
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +16 -1
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/request_context.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/{_auth.py → auth.py} +2 -0
- package/plugin/vendor/reflexio/reflexio/server/cache/reflexio_cache.py +62 -36
- package/plugin/vendor/reflexio/reflexio/server/deployment_profile.py +69 -0
- package/plugin/vendor/reflexio/reflexio/server/extensions.py +213 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_embedding.py +424 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_json_extraction.py +249 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_structured_output.py +195 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_subprocess.py +152 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_text_generation.py +980 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_types.py +110 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +73 -1819
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +57 -5
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/middleware.py +244 -0
- package/plugin/vendor/reflexio/reflexio/server/operation_limiter.py +9 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.4.0.prompt.md +14 -2
- package/plugin/vendor/reflexio/reflexio/server/rate_limit.py +79 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/__init__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/_common.py +25 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/_metering.py +98 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/braintrust.py +129 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/config.py +210 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/evaluation.py +549 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/interactions.py +259 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/playbooks.py +578 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/profiles.py +423 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/provenance.py +345 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/search.py +349 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/system.py +261 -0
- package/plugin/vendor/reflexio/reflexio/server/scheduling.py +132 -0
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +5 -2
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/__init__.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_batch_progress.py +298 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_config_filter.py +152 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_extraction_lifecycle.py +243 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_should_run.py +299 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_status_change.py +273 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_usage_billing.py +258 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +17 -1183
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +8 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +26 -41
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +8 -0
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +232 -123
- package/plugin/vendor/reflexio/reflexio/server/services/governance/config.py +52 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +378 -0
- package/plugin/vendor/reflexio/reflexio/server/services/governance/subject_refs.py +34 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +385 -78
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/README.md +9 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_prompt_processing.py +100 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator.py +121 -525
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_clustering.py +184 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_postprocessing.py +130 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator_prompt_formatting.py +212 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/consolidator.py +258 -69
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/service.py +9 -9
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/extractor.py +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/publish_learning_worker.py +288 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/recency.py +211 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +29 -13
- package/plugin/vendor/reflexio/reflexio/server/services/storage/error.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +681 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +43 -6
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +10 -1167
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +58 -351
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +49 -19
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +452 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +11 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_playbook.py +1 -2133
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_profiles.py +7 -1126
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +73 -33
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_share_links.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_agent_run_store.py +506 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_pending_tool_call_store.py +704 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/agent_run/_run_tool_dependency_store.py +123 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/__init__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_deletion.py +263 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_fts_vec.py +132 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_audit.py +122 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_erase_execution.py +465 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_purge.py +387 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_rebuild_hide.py +332 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_subject_barrier.py +511 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +955 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +189 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_optimization.py +247 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +145 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +844 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_interaction_store.py +263 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py +896 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_search.py +270 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +50 -9
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +64 -370
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_playbook.py +0 -909
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_requests.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_share_links.py +20 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_agent_run_store.py +86 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_models.py +195 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_pending_tool_call_store.py +148 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_run_tool_dependency_store.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_audit.py +29 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_erase_execution.py +30 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_purge.py +74 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_rebuild_hide.py +32 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/governance/_subject_barrier.py +49 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +365 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +124 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_optimization.py +85 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_source_linkage.py +47 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +333 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/__init__.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_interaction_store.py +73 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/{_profiles.py → profiles/_profile_store.py} +57 -86
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_search.py +32 -0
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +153 -12
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/user_detail_stripping.py +0 -84
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"plugins": [
|
|
10
10
|
{
|
|
11
11
|
"name": "claude-smart",
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.48",
|
|
13
13
|
"source": "./plugin",
|
|
14
14
|
"description": "Turns corrections into Preferences, Project-specific skills, and Shared skills — uses Claude Code, Codex, or OpenCode as the LLM backend (no external API key required)"
|
|
15
15
|
}
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License">
|
|
14
14
|
</a>
|
|
15
15
|
<a href="plugin/pyproject.toml">
|
|
16
|
-
<img src="https://img.shields.io/badge/version-0.2.
|
|
16
|
+
<img src="https://img.shields.io/badge/version-0.2.48-green.svg" alt="Version">
|
|
17
17
|
</a>
|
|
18
18
|
<a href="plugin/pyproject.toml">
|
|
19
19
|
<img src="https://img.shields.io/badge/python-%3E%3D3.12-brightgreen.svg" alt="Python">
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
<a href="https://discord.gg/7fnCxahase">
|
|
28
28
|
<img src="https://img.shields.io/badge/Discord-Join%20community-5865F2?logo=discord&logoColor=white" alt="Discord">
|
|
29
29
|
</a>
|
|
30
|
+
<a href="https://github.com/ReflexioAI/reflexio">
|
|
31
|
+
<img src="https://img.shields.io/github/stars/ReflexioAI/reflexio?style=flat&logo=github&label=Star%20reflexio&color=yellow&cacheSeconds=3600" alt="Star reflexio on GitHub">
|
|
32
|
+
</a>
|
|
30
33
|
</p>
|
|
31
34
|
|
|
32
35
|
<p align="center">
|
|
@@ -47,6 +50,10 @@
|
|
|
47
50
|
<b>vs <code>claude-mem</code>:</b> ~3× better at turning your corrections into rules Claude follows, ~50% more of your guidance is retained. <a href="EXPERIMENT.md"><b>Read the benchmark →</b></a>
|
|
48
51
|
</p>
|
|
49
52
|
|
|
53
|
+
<p align="center">
|
|
54
|
+
⭐ Built on the open-source <a href="https://github.com/ReflexioAI/reflexio"><b>reflexio</b></a> engine — if claude-smart helps you, <a href="https://github.com/ReflexioAI/reflexio"><b>star reflexio on GitHub</b></a>.
|
|
55
|
+
</p>
|
|
56
|
+
|
|
50
57
|
---
|
|
51
58
|
|
|
52
59
|
## Quick Start
|
|
@@ -54,12 +61,12 @@
|
|
|
54
61
|
### Claude Code
|
|
55
62
|
|
|
56
63
|
```bash
|
|
57
|
-
npx claude-smart install
|
|
64
|
+
npx claude-smart install
|
|
58
65
|
```
|
|
59
66
|
|
|
60
67
|
Then restart Claude Code.
|
|
61
68
|
|
|
62
|
-
Requires Node.js (for `npx`)
|
|
69
|
+
Requires Node.js (for `npx`) to already exist.
|
|
63
70
|
|
|
64
71
|
Alternatively, install via Claude Code's plugin marketplace:
|
|
65
72
|
|
|
@@ -71,7 +78,7 @@ claude plugin install claude-smart@reflexioai
|
|
|
71
78
|
To uninstall:
|
|
72
79
|
|
|
73
80
|
```bash
|
|
74
|
-
npx claude-smart uninstall
|
|
81
|
+
npx claude-smart uninstall
|
|
75
82
|
```
|
|
76
83
|
|
|
77
84
|
Or, if installed via the plugin marketplace:
|
|
@@ -104,9 +111,9 @@ Restart Codex after uninstalling. The uninstaller stops local claude-smart servi
|
|
|
104
111
|
npx claude-smart install --host opencode
|
|
105
112
|
```
|
|
106
113
|
|
|
107
|
-
Then restart OpenCode in your project so it loads the plugin from `opencode.json`, the documented project config file. If that project does not already have a root config but does have `.opencode/opencode.json` or `.opencode/opencode.jsonc`, the installer updates that existing file instead of creating a second config. If both locations exist, the root config wins. Use `--global` to install into `~/.config/opencode/opencode.json` for all OpenCode projects on this machine.
|
|
114
|
+
Then restart OpenCode in your project so it loads the plugin from `opencode.json`, the documented project config file. If that project does not already have a root config but does have `.opencode/opencode.json` or `.opencode/opencode.jsonc`, the installer updates that existing file instead of creating a second config. If both locations exist, the root config wins. Use `--global` to install into `~/.config/opencode/opencode.json` for all OpenCode projects on this machine. The installer copies the active package to `~/.claude-smart/opencode/claude-smart`, prepares that runtime immediately, and writes a `file://` plugin entry so OpenCode reloads the same prepared package after restart.
|
|
108
115
|
|
|
109
|
-
OpenCode support is new and uses OpenCode's
|
|
116
|
+
OpenCode support is new and uses OpenCode's plugin loader to inject relevant learned context before each model request. Learning extraction runs `opencode run --pure` from an isolated temp project, so it uses OpenCode's default model unless you set `CLAUDE_SMART_OPENCODE_MODEL=provider/model`. Set that env var if your normal project config pins a different provider or model.
|
|
110
117
|
|
|
111
118
|
To uninstall:
|
|
112
119
|
|
|
@@ -114,7 +121,7 @@ To uninstall:
|
|
|
114
121
|
npx claude-smart uninstall --host opencode
|
|
115
122
|
```
|
|
116
123
|
|
|
117
|
-
Restart OpenCode after uninstalling. The uninstaller removes
|
|
124
|
+
Restart OpenCode after uninstalling. The uninstaller removes the `claude-smart` entry from OpenCode's plugin list and deletes the copied OpenCode package; learned data under `~/.reflexio/` and `~/.claude-smart/` is preserved and shared across hosts.
|
|
118
125
|
|
|
119
126
|
Developing the plugin itself? See [DEVELOPER.md](./DEVELOPER.md#developing-locally) for what the installer does, manual toggles via `/plugins`, and clone-based development.
|
|
120
127
|
|
|
@@ -194,10 +201,10 @@ Under the hood: hooks watch your turns, tool calls, and assistant replies, auto-
|
|
|
194
201
|
**Citations.** At the end of a reply, the assistant may append a short marker:
|
|
195
202
|
|
|
196
203
|
```
|
|
197
|
-
✨
|
|
204
|
+
✨ claude-smart rule applied: [git safety](http://localhost:3001/rules/s1-123) | [brief answer preference](http://localhost:3001/rules/p1-pref) · [⚡Reflexio](https://github.com/ReflexioAI/reflexio)
|
|
198
205
|
```
|
|
199
206
|
|
|
200
|
-
That signals a preference
|
|
207
|
+
That signals a preference or skill materially shaped the reply.
|
|
201
208
|
Open the session's detail page in the [dashboard](http://localhost:3001) to see the exact cited item.
|
|
202
209
|
|
|
203
210
|
See [ARCHITECTURE.md](./ARCHITECTURE.md) for hooks, data flow, and reflexio details.
|
|
@@ -235,6 +242,7 @@ Advanced users can tune claude-smart via environment variables — see [DEVELOPE
|
|
|
235
242
|
| `~/.codex/config.toml` | Codex plugin state, hook feature flags, and per-hook trust entries after `claude-smart install --host codex`. |
|
|
236
243
|
| `~/.codex/plugins/cache/reflexioai/claude-smart/<version>/` | Codex's cached install of the `claude-smart` plugin from the `ReflexioAI` marketplace. |
|
|
237
244
|
| `opencode.json` / `opencode.jsonc`, or existing `.opencode/opencode.json*` | OpenCode local plugin config patched by `claude-smart install --host opencode`; the installer updates only the claude-smart entry in OpenCode's plugin list. |
|
|
245
|
+
| `~/.claude-smart/opencode/claude-smart/` | OpenCode's stable local copy of the active npm package. OpenCode config points here with `file://` so restarts do not re-resolve `claude-smart` from npm. |
|
|
238
246
|
| `~/.reflexio/plugin-root` | Self-healed symlink to the active plugin dir (managed by `ensure-plugin-root.sh` — written on install, refreshed each `SessionStart`). Claude Code slash commands and Codex shell-command helpers resolve through it, so don't delete it; if you do, the next session will recreate it. |
|
|
239
247
|
| `~/.claude-smart/sessions/{session_id}.jsonl` | Per-session buffer. User turns, assistant turns, tool invocations, `{"published_up_to": N}` watermarks. Safe to inspect and safe to delete — everything past the latest watermark has already been written to reflexio's DB. |
|
|
240
248
|
| `~/.claude-smart/node/current/` | Private Node.js/npm runtime used by hooks and the dashboard after install. |
|
|
@@ -246,7 +254,7 @@ For troubleshooting, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
|
|
|
246
254
|
|
|
247
255
|
## Powered by Reflexio
|
|
248
256
|
|
|
249
|
-
claude-smart is powered by [**Reflexio**](https://reflexio.ai) — the self-improving engine that turns interactions into durable, reusable skills.
|
|
257
|
+
claude-smart is powered by [**Reflexio**](https://github.com/ReflexioAI/reflexio) ([reflexio.ai](https://reflexio.ai)) — the open-source self-improving engine that turns interactions into durable, reusable skills. If claude-smart is useful to you, **[⭐ star reflexio on GitHub](https://github.com/ReflexioAI/reflexio)**.
|
|
250
258
|
|
|
251
259
|
---
|
|
252
260
|
|
|
@@ -265,4 +273,4 @@ See the [LICENSE](LICENSE) file for details.
|
|
|
265
273
|
|
|
266
274
|
---
|
|
267
275
|
|
|
268
|
-
**Powered by** [Reflexio](https://reflexio
|
|
276
|
+
**Powered by** [Reflexio](https://github.com/ReflexioAI/reflexio) · **Runs on** [Claude Code](https://claude.com/claude-code), Codex, and OpenCode · **Written in** Python 3.12+
|
package/bin/claude-smart.js
CHANGED
|
@@ -25,7 +25,9 @@ const {
|
|
|
25
25
|
mkdirSync,
|
|
26
26
|
readFileSync,
|
|
27
27
|
readdirSync,
|
|
28
|
+
realpathSync,
|
|
28
29
|
renameSync,
|
|
30
|
+
rmdirSync,
|
|
29
31
|
rmSync,
|
|
30
32
|
statSync,
|
|
31
33
|
symlinkSync,
|
|
@@ -33,13 +35,14 @@ const {
|
|
|
33
35
|
} = require("fs");
|
|
34
36
|
const https = require("https");
|
|
35
37
|
const { arch, homedir, platform, release, tmpdir } = require("os");
|
|
36
|
-
const { dirname, join } = require("path");
|
|
38
|
+
const { dirname, join, resolve } = require("path");
|
|
39
|
+
const { fileURLToPath, pathToFileURL } = require("url");
|
|
37
40
|
|
|
38
41
|
const PLUGIN_SPEC = "claude-smart@reflexioai";
|
|
39
42
|
const CODEX_MARKETPLACE_NAME = "reflexioai";
|
|
40
43
|
const CODEX_MARKETPLACE_DISPLAY_NAME = "ReflexioAI";
|
|
41
44
|
const CODEX_PLUGIN_ID = `claude-smart@${CODEX_MARKETPLACE_NAME}`;
|
|
42
|
-
const
|
|
45
|
+
const OPENCODE_BARE_PLUGIN_SPEC = "claude-smart";
|
|
43
46
|
const OPENCODE_CONFIG_NAMES = ["opencode.json", "opencode.jsonc"];
|
|
44
47
|
const REFLEXIO_ENV_PATH = join(homedir(), ".reflexio", ".env");
|
|
45
48
|
const MANAGED_REFLEXIO_URL = "https://www.reflexio.ai/";
|
|
@@ -50,6 +53,9 @@ const CLAUDE_SMART_USE_LOCAL_EMBEDDING_ENV = "CLAUDE_SMART_USE_LOCAL_EMBEDDING";
|
|
|
50
53
|
const REFLEXIO_USER_ID_ENV = "REFLEXIO_USER_ID";
|
|
51
54
|
const REFLEXIO_DIR = join(homedir(), ".reflexio");
|
|
52
55
|
const CLAUDE_SMART_STATE_DIR = join(homedir(), ".claude-smart");
|
|
56
|
+
const OPENCODE_LOCAL_PACKAGE_DIR = join(CLAUDE_SMART_STATE_DIR, "opencode", "claude-smart");
|
|
57
|
+
const OPENCODE_PACKAGE_LOCK_TIMEOUT_MS = 120_000;
|
|
58
|
+
const OPENCODE_PACKAGE_LOCK_STALE_MS = 10 * 60_000;
|
|
53
59
|
const CODEX_CONFIG_PATH = join(homedir(), ".codex", "config.toml");
|
|
54
60
|
const PACKAGE_ROOT = dirname(dirname(__filename));
|
|
55
61
|
const CODEX_MARKETPLACE_DIR = join(
|
|
@@ -96,6 +102,7 @@ const COPYTREE_IGNORE_NAMES = new Set([
|
|
|
96
102
|
".venv",
|
|
97
103
|
".pytest_cache",
|
|
98
104
|
".ruff_cache",
|
|
105
|
+
".git",
|
|
99
106
|
"node_modules",
|
|
100
107
|
".next",
|
|
101
108
|
]);
|
|
@@ -450,7 +457,41 @@ function opencodePluginSpec(entry) {
|
|
|
450
457
|
return null;
|
|
451
458
|
}
|
|
452
459
|
|
|
453
|
-
function
|
|
460
|
+
function opencodeLocalPluginSpec(packageRoot = OPENCODE_LOCAL_PACKAGE_DIR) {
|
|
461
|
+
return pathToFileURL(packageRoot).href;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function isOpenCodeLocalPackagePath(packagePath) {
|
|
465
|
+
return (
|
|
466
|
+
sameRealPath(packagePath, OPENCODE_LOCAL_PACKAGE_DIR) ||
|
|
467
|
+
resolve(packagePath) === resolve(OPENCODE_LOCAL_PACKAGE_DIR)
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function isOpenCodeClaudeSmartSpec(spec) {
|
|
472
|
+
if (!spec) return false;
|
|
473
|
+
if (spec === OPENCODE_BARE_PLUGIN_SPEC || spec.startsWith(`${OPENCODE_BARE_PLUGIN_SPEC}@`)) {
|
|
474
|
+
return true;
|
|
475
|
+
}
|
|
476
|
+
if (!spec.startsWith("file://")) return false;
|
|
477
|
+
let packagePath = null;
|
|
478
|
+
try {
|
|
479
|
+
packagePath = fileURLToPath(spec);
|
|
480
|
+
} catch {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
if (isOpenCodeLocalPackagePath(packagePath)) return true;
|
|
484
|
+
try {
|
|
485
|
+
const manifest = JSON.parse(readFileSync(join(packagePath, "package.json"), "utf8"));
|
|
486
|
+
if (manifest && manifest.name === OPENCODE_BARE_PLUGIN_SPEC) return true;
|
|
487
|
+
} catch {
|
|
488
|
+
// Missing or malformed manifests are not enough to identify arbitrary file specs.
|
|
489
|
+
}
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function patchOpenCodePluginConfig(configPath, { install, pluginSpec = null }) {
|
|
494
|
+
const resolvedPluginSpec = install ? (pluginSpec || opencodeLocalPluginSpec()) : pluginSpec;
|
|
454
495
|
const data = readJsoncObject(configPath);
|
|
455
496
|
for (const field of ["plugins", "plugin"]) {
|
|
456
497
|
if (data[field] !== undefined && !Array.isArray(data[field])) {
|
|
@@ -461,8 +502,8 @@ function patchOpenCodePluginConfig(configPath, { install }) {
|
|
|
461
502
|
...(Array.isArray(data.plugin) ? data.plugin : []),
|
|
462
503
|
...(Array.isArray(data.plugins) ? data.plugins : []),
|
|
463
504
|
];
|
|
464
|
-
const kept = current.filter((entry) => opencodePluginSpec(entry)
|
|
465
|
-
const next = install ? [...kept,
|
|
505
|
+
const kept = current.filter((entry) => !isOpenCodeClaudeSmartSpec(opencodePluginSpec(entry)));
|
|
506
|
+
const next = install ? [...kept, resolvedPluginSpec] : kept;
|
|
466
507
|
const changed =
|
|
467
508
|
data.plugins !== undefined ||
|
|
468
509
|
(Array.isArray(data.plugin)
|
|
@@ -484,10 +525,6 @@ function patchOpenCodePluginConfig(configPath, { install }) {
|
|
|
484
525
|
return { changed: true, configPath, backupPath };
|
|
485
526
|
}
|
|
486
527
|
|
|
487
|
-
function isNpxPackageRoot(path) {
|
|
488
|
-
return path.split(/[\\/]+/).includes("_npx");
|
|
489
|
-
}
|
|
490
|
-
|
|
491
528
|
function hasExtractionProvider() {
|
|
492
529
|
if ((process.env.REFLEXIO_API_KEY || "").trim()) return true;
|
|
493
530
|
const cliPath = (process.env.CLAUDE_SMART_CLI_PATH || "").trim();
|
|
@@ -600,6 +637,130 @@ function forcePluginRoot(pluginRoot) {
|
|
|
600
637
|
}
|
|
601
638
|
}
|
|
602
639
|
|
|
640
|
+
function sameRealPath(left, right) {
|
|
641
|
+
try {
|
|
642
|
+
return realpathSync(left) === realpathSync(right);
|
|
643
|
+
} catch {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function pathEntryExists(path) {
|
|
649
|
+
try {
|
|
650
|
+
lstatSync(path);
|
|
651
|
+
return true;
|
|
652
|
+
} catch {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function fileSha256(path) {
|
|
658
|
+
return crypto.createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function verifyOpenCodePluginPackage(packageRoot) {
|
|
662
|
+
const sourceScript = join(PACKAGE_ROOT, "plugin", "scripts", "smart-install.sh");
|
|
663
|
+
const copiedScript = join(packageRoot, "plugin", "scripts", "smart-install.sh");
|
|
664
|
+
for (const file of [join(packageRoot, "package.json"), copiedScript]) {
|
|
665
|
+
if (!existsSync(file)) {
|
|
666
|
+
throw new Error(`OpenCode local plugin package is missing ${file}`);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (fileSha256(sourceScript) !== fileSha256(copiedScript)) {
|
|
670
|
+
throw new Error(
|
|
671
|
+
"OpenCode local plugin package does not match the installed claude-smart package",
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function sleepSync(ms) {
|
|
677
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function withOpenCodePackageInstallLock(fn) {
|
|
681
|
+
const lockDir = join(dirname(OPENCODE_LOCAL_PACKAGE_DIR), ".install.lock");
|
|
682
|
+
mkdirSync(dirname(OPENCODE_LOCAL_PACKAGE_DIR), { recursive: true });
|
|
683
|
+
const deadline = Date.now() + OPENCODE_PACKAGE_LOCK_TIMEOUT_MS;
|
|
684
|
+
while (true) {
|
|
685
|
+
try {
|
|
686
|
+
mkdirSync(lockDir);
|
|
687
|
+
break;
|
|
688
|
+
} catch (err) {
|
|
689
|
+
if (!err || err.code !== "EEXIST") throw err;
|
|
690
|
+
try {
|
|
691
|
+
if (Date.now() - statSync(lockDir).mtimeMs > OPENCODE_PACKAGE_LOCK_STALE_MS) {
|
|
692
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
} catch (statErr) {
|
|
696
|
+
if (statErr && statErr.code !== "ENOENT") throw statErr;
|
|
697
|
+
}
|
|
698
|
+
if (Date.now() >= deadline) {
|
|
699
|
+
throw new Error(`timed out waiting for OpenCode package install lock at ${lockDir}`);
|
|
700
|
+
}
|
|
701
|
+
sleepSync(100);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
try {
|
|
705
|
+
return fn();
|
|
706
|
+
} finally {
|
|
707
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function uniqueOpenCodePackagePath(prefix) {
|
|
712
|
+
return join(
|
|
713
|
+
dirname(OPENCODE_LOCAL_PACKAGE_DIR),
|
|
714
|
+
`${prefix}-${process.pid}-${Date.now()}-${crypto.randomBytes(4).toString("hex")}`,
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function replaceOpenCodePluginPackage(stagedPackage, packageRoot) {
|
|
719
|
+
const backupPackage = uniqueOpenCodePackagePath(".claude-smart-previous");
|
|
720
|
+
let backupCreated = false;
|
|
721
|
+
try {
|
|
722
|
+
if (pathEntryExists(packageRoot)) {
|
|
723
|
+
renameSync(packageRoot, backupPackage);
|
|
724
|
+
backupCreated = true;
|
|
725
|
+
}
|
|
726
|
+
renameSync(stagedPackage, packageRoot);
|
|
727
|
+
if (backupCreated) {
|
|
728
|
+
rmSync(backupPackage, { recursive: true, force: true });
|
|
729
|
+
}
|
|
730
|
+
} catch (err) {
|
|
731
|
+
if (backupCreated && !existsSync(packageRoot) && existsSync(backupPackage)) {
|
|
732
|
+
renameSync(backupPackage, packageRoot);
|
|
733
|
+
}
|
|
734
|
+
throw err;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
function installOpenCodePluginPackage() {
|
|
739
|
+
const packageRoot = OPENCODE_LOCAL_PACKAGE_DIR;
|
|
740
|
+
if (sameRealPath(PACKAGE_ROOT, packageRoot)) {
|
|
741
|
+
verifyOpenCodePluginPackage(packageRoot);
|
|
742
|
+
return packageRoot;
|
|
743
|
+
}
|
|
744
|
+
return withOpenCodePackageInstallLock(() => {
|
|
745
|
+
const stagedPackage = uniqueOpenCodePackagePath(".claude-smart-copy");
|
|
746
|
+
rmSync(stagedPackage, { recursive: true, force: true });
|
|
747
|
+
try {
|
|
748
|
+
cpSync(PACKAGE_ROOT, stagedPackage, {
|
|
749
|
+
recursive: true,
|
|
750
|
+
force: true,
|
|
751
|
+
verbatimSymlinks: false,
|
|
752
|
+
filter: shouldCopyPath,
|
|
753
|
+
});
|
|
754
|
+
verifyOpenCodePluginPackage(stagedPackage);
|
|
755
|
+
replaceOpenCodePluginPackage(stagedPackage, packageRoot);
|
|
756
|
+
verifyOpenCodePluginPackage(packageRoot);
|
|
757
|
+
return packageRoot;
|
|
758
|
+
} finally {
|
|
759
|
+
rmSync(stagedPackage, { recursive: true, force: true });
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
603
764
|
async function bootstrapClaudeCodeInstall() {
|
|
604
765
|
const pluginRoot = findClaudeCodePluginRoot();
|
|
605
766
|
if (!pluginRoot) {
|
|
@@ -694,6 +855,18 @@ function runChecked(command, args, options = {}) {
|
|
|
694
855
|
});
|
|
695
856
|
}
|
|
696
857
|
|
|
858
|
+
function runSilentStatus(command, args, options = {}) {
|
|
859
|
+
const result = spawnSync(command, args, {
|
|
860
|
+
cwd: options.cwd,
|
|
861
|
+
env: options.env || process.env,
|
|
862
|
+
shell: isWindows() && /\.(?:cmd|bat)$/i.test(command),
|
|
863
|
+
stdio: "ignore",
|
|
864
|
+
windowsHide: true,
|
|
865
|
+
});
|
|
866
|
+
if (result.error || result.signal) return 1;
|
|
867
|
+
return typeof result.status === "number" ? result.status : 1;
|
|
868
|
+
}
|
|
869
|
+
|
|
697
870
|
function runPluginService(pluginRoot, scriptName, subcommand, envOverrides = {}) {
|
|
698
871
|
const script = join(pluginRoot, "scripts", scriptName);
|
|
699
872
|
if (!existsSync(script)) return false;
|
|
@@ -1092,6 +1265,59 @@ async function installVendoredReflexio(pluginRoot, uv, env) {
|
|
|
1092
1265
|
if (code !== 0) throw new Error(`vendored Reflexio install failed in ${pluginRoot}`);
|
|
1093
1266
|
}
|
|
1094
1267
|
|
|
1268
|
+
async function syncPluginPythonEnv(pluginRoot, uv, env) {
|
|
1269
|
+
let code = await runChecked(
|
|
1270
|
+
uv,
|
|
1271
|
+
["sync", "--locked", "--python", "3.12", "--quiet"],
|
|
1272
|
+
{ cwd: pluginRoot, env },
|
|
1273
|
+
);
|
|
1274
|
+
if (code === 0) return;
|
|
1275
|
+
|
|
1276
|
+
const lockIsFresh = runSilentStatus(
|
|
1277
|
+
uv,
|
|
1278
|
+
["lock", "--check", "--python", "3.12"],
|
|
1279
|
+
{ cwd: pluginRoot, env },
|
|
1280
|
+
) === 0;
|
|
1281
|
+
if (lockIsFresh) {
|
|
1282
|
+
process.stderr.write(
|
|
1283
|
+
`warning: quiet uv sync failed in ${pluginRoot}; retrying with full output.\n`,
|
|
1284
|
+
);
|
|
1285
|
+
code = await runChecked(
|
|
1286
|
+
uv,
|
|
1287
|
+
["sync", "--locked", "--python", "3.12"],
|
|
1288
|
+
{ cwd: pluginRoot, env },
|
|
1289
|
+
);
|
|
1290
|
+
if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
process.stderr.write(
|
|
1295
|
+
"warning: plugin/uv.lock is out of sync; refreshing local lockfile and retrying uv sync.\n",
|
|
1296
|
+
);
|
|
1297
|
+
code = await runChecked(
|
|
1298
|
+
uv,
|
|
1299
|
+
["lock", "--python", "3.12"],
|
|
1300
|
+
{ cwd: pluginRoot, env },
|
|
1301
|
+
);
|
|
1302
|
+
if (code !== 0) throw new Error(`uv lock failed in ${pluginRoot}`);
|
|
1303
|
+
code = await runChecked(
|
|
1304
|
+
uv,
|
|
1305
|
+
["sync", "--python", "3.12", "--quiet"],
|
|
1306
|
+
{ cwd: pluginRoot, env },
|
|
1307
|
+
);
|
|
1308
|
+
if (code !== 0) {
|
|
1309
|
+
process.stderr.write(
|
|
1310
|
+
`warning: quiet uv sync failed in ${pluginRoot} after refreshing plugin/uv.lock; retrying with full output.\n`,
|
|
1311
|
+
);
|
|
1312
|
+
code = await runChecked(
|
|
1313
|
+
uv,
|
|
1314
|
+
["sync", "--python", "3.12"],
|
|
1315
|
+
{ cwd: pluginRoot, env },
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1095
1321
|
async function bootstrapPluginRuntime(pluginRoot, options = {}) {
|
|
1096
1322
|
assertSupportedRuntimePlatform();
|
|
1097
1323
|
process.stdout.write("Preparing claude-smart runtime for hooks...\n");
|
|
@@ -1113,27 +1339,12 @@ async function bootstrapPluginRuntime(pluginRoot, options = {}) {
|
|
|
1113
1339
|
);
|
|
1114
1340
|
if (lockCode !== 0) throw new Error(`uv lock failed in ${pluginRoot}`);
|
|
1115
1341
|
}
|
|
1116
|
-
|
|
1117
|
-
uv,
|
|
1118
|
-
["sync", "--locked", "--python", "3.12", "--quiet"],
|
|
1119
|
-
{ cwd: pluginRoot, env },
|
|
1120
|
-
);
|
|
1121
|
-
if (code !== 0) {
|
|
1122
|
-
process.stderr.write(
|
|
1123
|
-
`warning: quiet uv sync failed in ${pluginRoot}; retrying with full output.\n`,
|
|
1124
|
-
);
|
|
1125
|
-
code = await runChecked(
|
|
1126
|
-
uv,
|
|
1127
|
-
["sync", "--locked", "--python", "3.12"],
|
|
1128
|
-
{ cwd: pluginRoot, env },
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
if (code !== 0) throw new Error(`uv sync failed in ${pluginRoot}`);
|
|
1342
|
+
await syncPluginPythonEnv(pluginRoot, uv, env);
|
|
1132
1343
|
await installVendoredReflexio(pluginRoot, uv, env);
|
|
1133
1344
|
|
|
1134
1345
|
const dashboardDir = join(pluginRoot, "dashboard");
|
|
1135
1346
|
if (existsSync(dashboardDir)) {
|
|
1136
|
-
code = await runChecked(nodeRuntime.npm, ["ci"], { cwd: dashboardDir, env });
|
|
1347
|
+
let code = await runChecked(nodeRuntime.npm, ["ci"], { cwd: dashboardDir, env });
|
|
1137
1348
|
if (code !== 0) throw new Error(`npm ci failed in ${dashboardDir}`);
|
|
1138
1349
|
code = await runChecked(nodeRuntime.npm, ["run", "build"], { cwd: dashboardDir, env });
|
|
1139
1350
|
if (code !== 0) throw new Error(`npm run build failed in ${dashboardDir}`);
|
|
@@ -1169,9 +1380,10 @@ function printHelp() {
|
|
|
1169
1380
|
" 7. Restart Codex.",
|
|
1170
1381
|
"",
|
|
1171
1382
|
"OpenCode install:",
|
|
1172
|
-
|
|
1173
|
-
" 2.
|
|
1174
|
-
" 3.
|
|
1383
|
+
` 1. Copies this package to ${OPENCODE_LOCAL_PACKAGE_DIR}`,
|
|
1384
|
+
" 2. Adds that local file:// package to OpenCode's plugin list in opencode.json",
|
|
1385
|
+
" 3. Prepares local services now from the copied plugin runtime",
|
|
1386
|
+
" 4. Restart OpenCode.",
|
|
1175
1387
|
"",
|
|
1176
1388
|
"Update:",
|
|
1177
1389
|
" npx claude-smart update Reinstall Claude Code support from this package",
|
|
@@ -1894,43 +2106,44 @@ async function runInstallOpenCode(args) {
|
|
|
1894
2106
|
process.exit(1);
|
|
1895
2107
|
}
|
|
1896
2108
|
|
|
1897
|
-
|
|
2109
|
+
let packageRoot;
|
|
2110
|
+
try {
|
|
2111
|
+
packageRoot = installOpenCodePluginPackage();
|
|
2112
|
+
} catch (err) {
|
|
2113
|
+
process.stderr.write(
|
|
2114
|
+
`error: could not prepare claude-smart OpenCode package: ${err && err.message ? err.message : err}\n`,
|
|
2115
|
+
);
|
|
2116
|
+
process.exit(1);
|
|
2117
|
+
}
|
|
2118
|
+
const pluginRoot = join(packageRoot, "plugin");
|
|
2119
|
+
const pluginSpec = opencodeLocalPluginSpec(packageRoot);
|
|
1898
2120
|
let result;
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
process.exit(1);
|
|
1905
|
-
}
|
|
1906
|
-
process.stdout.write(
|
|
1907
|
-
"Skipped starting claude-smart services from npx's temporary package cache; OpenCode will prepare the runtime from its installed plugin package on next launch.\n",
|
|
2121
|
+
try {
|
|
2122
|
+
await bootstrapPluginRuntime(pluginRoot, { readOnly, patchCodexHooks: false });
|
|
2123
|
+
} catch (err) {
|
|
2124
|
+
process.stderr.write(
|
|
2125
|
+
`error: claude-smart OpenCode setup failed during dependency bootstrap: ${err && err.message ? err.message : err}\n`,
|
|
1908
2126
|
);
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
process.stdout.write("Started claude-smart backend service.\n");
|
|
1930
|
-
}
|
|
1931
|
-
if (refreshDashboardService(pluginRoot)) {
|
|
1932
|
-
process.stdout.write("Refreshed claude-smart dashboard service.\n");
|
|
1933
|
-
}
|
|
2127
|
+
process.exit(1);
|
|
2128
|
+
}
|
|
2129
|
+
try {
|
|
2130
|
+
result = patchOpenCodePluginConfig(opencodeConfigPath(args), {
|
|
2131
|
+
install: true,
|
|
2132
|
+
pluginSpec,
|
|
2133
|
+
});
|
|
2134
|
+
} catch (err) {
|
|
2135
|
+
process.stderr.write(`error: could not update OpenCode config: ${err && err.message ? err.message : err}\n`);
|
|
2136
|
+
stopClaudeSmartServices(pluginRoot);
|
|
2137
|
+
process.exit(1);
|
|
2138
|
+
}
|
|
2139
|
+
if (readOnly) {
|
|
2140
|
+
process.stdout.write("Installed read-only hook manifest; publish interactions hooks are disabled.\n");
|
|
2141
|
+
}
|
|
2142
|
+
if (startBackendService(pluginRoot, "opencode")) {
|
|
2143
|
+
process.stdout.write("Started claude-smart backend service.\n");
|
|
2144
|
+
}
|
|
2145
|
+
if (refreshDashboardService(pluginRoot)) {
|
|
2146
|
+
process.stdout.write("Refreshed claude-smart dashboard service.\n");
|
|
1934
2147
|
}
|
|
1935
2148
|
if (result.backupPath) {
|
|
1936
2149
|
process.stdout.write(`Saved a comment-preserving backup of your previous config at ${result.backupPath}.\n`);
|
|
@@ -1938,7 +2151,8 @@ async function runInstallOpenCode(args) {
|
|
|
1938
2151
|
process.stdout.write(
|
|
1939
2152
|
[
|
|
1940
2153
|
"",
|
|
1941
|
-
`${result.changed ? "Updated" : "OpenCode config already includes"} "${
|
|
2154
|
+
`${result.changed ? "Updated" : "OpenCode config already includes"} "${pluginSpec}" in ${result.configPath}.`,
|
|
2155
|
+
`Prepared claude-smart OpenCode package at ${packageRoot}.`,
|
|
1942
2156
|
"claude-smart OpenCode support is installed.",
|
|
1943
2157
|
"Restart OpenCode in your project so it loads the plugin.",
|
|
1944
2158
|
"",
|
|
@@ -1975,6 +2189,7 @@ async function runUninstallCodex() {
|
|
|
1975
2189
|
|
|
1976
2190
|
async function runUninstallOpenCode(args) {
|
|
1977
2191
|
stopClaudeSmartServices(join(PACKAGE_ROOT, "plugin"));
|
|
2192
|
+
stopClaudeSmartServices(join(OPENCODE_LOCAL_PACKAGE_DIR, "plugin"));
|
|
1978
2193
|
let result;
|
|
1979
2194
|
try {
|
|
1980
2195
|
result = patchOpenCodePluginConfig(opencodeConfigPath(args), { install: false });
|
|
@@ -1985,12 +2200,18 @@ async function runUninstallOpenCode(args) {
|
|
|
1985
2200
|
if (result.backupPath) {
|
|
1986
2201
|
process.stdout.write(`Saved a comment-preserving backup of your previous config at ${result.backupPath}.\n`);
|
|
1987
2202
|
}
|
|
2203
|
+
rmSync(OPENCODE_LOCAL_PACKAGE_DIR, { recursive: true, force: true });
|
|
2204
|
+
try {
|
|
2205
|
+
rmdirSync(dirname(OPENCODE_LOCAL_PACKAGE_DIR));
|
|
2206
|
+
} catch {
|
|
2207
|
+
// Keep the parent when it still contains future OpenCode state.
|
|
2208
|
+
}
|
|
1988
2209
|
process.stdout.write(
|
|
1989
2210
|
[
|
|
1990
2211
|
"",
|
|
1991
2212
|
result.changed
|
|
1992
|
-
? `Removed
|
|
1993
|
-
:
|
|
2213
|
+
? `Removed claude-smart OpenCode plugin entries from ${result.configPath}.`
|
|
2214
|
+
: "OpenCode config did not include claude-smart.",
|
|
1994
2215
|
"Restart OpenCode to apply.",
|
|
1995
2216
|
...LOCAL_DATA_NOTICE,
|
|
1996
2217
|
"",
|
|
@@ -2050,7 +2271,8 @@ module.exports = {
|
|
|
2050
2271
|
configureReflexioSetup,
|
|
2051
2272
|
patchCodexHooksForNode,
|
|
2052
2273
|
opencodeConfigPath,
|
|
2053
|
-
|
|
2274
|
+
opencodeLocalPluginSpec,
|
|
2275
|
+
installOpenCodePluginPackage,
|
|
2054
2276
|
patchOpenCodePluginConfig,
|
|
2055
2277
|
hasExtractionProvider,
|
|
2056
2278
|
platformSupportError,
|
package/package.json
CHANGED