claude-smart 0.2.22 → 0.2.24
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/.agents/plugins/marketplace.json +20 -0
- package/README.md +69 -27
- package/bin/claude-smart.js +296 -11
- package/package.json +11 -1
- package/plugin/.claude-plugin/plugin.json +17 -0
- package/plugin/.codex-plugin/plugin.json +35 -0
- package/plugin/LICENSE +202 -0
- package/plugin/README.md +37 -0
- package/plugin/bin/cs-cite +77 -0
- package/plugin/commands/clear-all.md +8 -0
- package/plugin/commands/dashboard.md +8 -0
- package/plugin/commands/learn.md +12 -0
- package/plugin/commands/restart.md +8 -0
- package/plugin/commands/show.md +8 -0
- package/plugin/dashboard/AGENTS.md +6 -0
- package/plugin/dashboard/app/api/claude-settings/route.ts +19 -0
- package/plugin/dashboard/app/api/config/route.ts +16 -0
- package/plugin/dashboard/app/api/health/route.ts +10 -0
- package/plugin/dashboard/app/api/reflexio/[...path]/route.ts +63 -0
- package/plugin/dashboard/app/api/sessions/[id]/route.ts +28 -0
- package/plugin/dashboard/app/api/sessions/route.ts +14 -0
- package/plugin/dashboard/app/configure/env/page.tsx +318 -0
- package/plugin/dashboard/app/configure/layout.tsx +47 -0
- package/plugin/dashboard/app/configure/page.tsx +5 -0
- package/plugin/dashboard/app/configure/server/page.tsx +258 -0
- package/plugin/dashboard/app/dashboard/page.tsx +227 -0
- package/plugin/dashboard/app/globals.css +129 -0
- package/plugin/dashboard/app/icon.png +0 -0
- package/plugin/dashboard/app/layout.tsx +40 -0
- package/plugin/dashboard/app/page.tsx +5 -0
- package/plugin/dashboard/app/preferences/[id]/page.tsx +531 -0
- package/plugin/dashboard/app/preferences/page.tsx +126 -0
- package/plugin/dashboard/app/providers.tsx +12 -0
- package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +321 -0
- package/plugin/dashboard/app/sessions/page.tsx +186 -0
- package/plugin/dashboard/app/skills/page.tsx +362 -0
- package/plugin/dashboard/app/skills/project/[id]/page.tsx +597 -0
- package/plugin/dashboard/app/skills/shared/[id]/page.tsx +830 -0
- package/plugin/dashboard/components/common/delete-all-button.tsx +45 -0
- package/plugin/dashboard/components/common/empty-state.tsx +34 -0
- package/plugin/dashboard/components/common/learnings-badge.tsx +34 -0
- package/plugin/dashboard/components/common/page-header.tsx +34 -0
- package/plugin/dashboard/components/common/page-tabs.tsx +115 -0
- package/plugin/dashboard/components/common/stat-card.tsx +38 -0
- package/plugin/dashboard/components/layout/nav-items.ts +22 -0
- package/plugin/dashboard/components/layout/sidebar.tsx +45 -0
- package/plugin/dashboard/components/layout/top-bar.tsx +64 -0
- package/plugin/dashboard/components/stall-banner.tsx +53 -0
- package/plugin/dashboard/components/ui/badge.tsx +52 -0
- package/plugin/dashboard/components/ui/button.tsx +60 -0
- package/plugin/dashboard/components/ui/collapsible.tsx +21 -0
- package/plugin/dashboard/components/ui/input.tsx +20 -0
- package/plugin/dashboard/components/ui/label.tsx +20 -0
- package/plugin/dashboard/components/ui/scroll-area.tsx +55 -0
- package/plugin/dashboard/components/ui/select.tsx +201 -0
- package/plugin/dashboard/components/ui/separator.tsx +25 -0
- package/plugin/dashboard/components/ui/sheet.tsx +135 -0
- package/plugin/dashboard/components/ui/switch.tsx +32 -0
- package/plugin/dashboard/components.json +25 -0
- package/plugin/dashboard/eslint.config.mjs +16 -0
- package/plugin/dashboard/hooks/use-settings.tsx +88 -0
- package/plugin/dashboard/hooks/use-stall-state.ts +59 -0
- package/plugin/dashboard/lib/claude-settings-file.ts +114 -0
- package/plugin/dashboard/lib/config-file.ts +131 -0
- package/plugin/dashboard/lib/format.ts +58 -0
- package/plugin/dashboard/lib/reflexio-client.ts +238 -0
- package/plugin/dashboard/lib/reflexio-url.ts +17 -0
- package/plugin/dashboard/lib/session-reader.ts +245 -0
- package/plugin/dashboard/lib/status.ts +24 -0
- package/plugin/dashboard/lib/types.ts +145 -0
- package/plugin/dashboard/lib/utils.ts +6 -0
- package/plugin/dashboard/next.config.ts +7 -0
- package/plugin/dashboard/package-lock.json +10275 -0
- package/plugin/dashboard/package.json +37 -0
- package/plugin/dashboard/postcss.config.mjs +7 -0
- package/plugin/dashboard/public/claude-smart-icon.png +0 -0
- package/plugin/dashboard/tsconfig.json +34 -0
- package/plugin/hooks/codex-hooks.json +67 -0
- package/plugin/hooks/hooks.json +111 -0
- package/plugin/pyproject.toml +49 -0
- package/plugin/scripts/_codex_env.sh +27 -0
- package/plugin/scripts/_lib.sh +325 -0
- package/plugin/scripts/backend-service.sh +208 -0
- package/plugin/scripts/cli.sh +40 -0
- package/plugin/scripts/dashboard-build.sh +139 -0
- package/plugin/scripts/dashboard-open.sh +107 -0
- package/plugin/scripts/dashboard-service.sh +195 -0
- package/plugin/scripts/ensure-plugin-root.sh +84 -0
- package/plugin/scripts/hook_entry.sh +70 -0
- package/plugin/scripts/smart-install.sh +411 -0
- package/plugin/src/claude_smart/__init__.py +3 -0
- package/plugin/src/claude_smart/cli.py +1273 -0
- package/plugin/src/claude_smart/context_format.py +277 -0
- package/plugin/src/claude_smart/context_inject.py +92 -0
- package/plugin/src/claude_smart/cs_cite.py +236 -0
- package/plugin/src/claude_smart/events/__init__.py +1 -0
- package/plugin/src/claude_smart/events/post_tool.py +148 -0
- package/plugin/src/claude_smart/events/pre_tool.py +52 -0
- package/plugin/src/claude_smart/events/session_end.py +20 -0
- package/plugin/src/claude_smart/events/session_start.py +119 -0
- package/plugin/src/claude_smart/events/stop.py +393 -0
- package/plugin/src/claude_smart/events/user_prompt.py +73 -0
- package/plugin/src/claude_smart/hook.py +114 -0
- package/plugin/src/claude_smart/ids.py +56 -0
- package/plugin/src/claude_smart/internal_call.py +89 -0
- package/plugin/src/claude_smart/optimizer_assistant.py +203 -0
- package/plugin/src/claude_smart/publish.py +71 -0
- package/plugin/src/claude_smart/query_compose.py +51 -0
- package/plugin/src/claude_smart/reflexio_adapter.py +403 -0
- package/plugin/src/claude_smart/runtime.py +52 -0
- package/plugin/src/claude_smart/stall_banner.py +61 -0
- package/plugin/src/claude_smart/state.py +276 -0
- package/plugin/uv.lock +3720 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reflexioai",
|
|
3
|
+
"interface": {
|
|
4
|
+
"displayName": "ReflexioAI"
|
|
5
|
+
},
|
|
6
|
+
"plugins": [
|
|
7
|
+
{
|
|
8
|
+
"name": "claude-smart",
|
|
9
|
+
"source": {
|
|
10
|
+
"source": "local",
|
|
11
|
+
"path": "./plugin"
|
|
12
|
+
},
|
|
13
|
+
"policy": {
|
|
14
|
+
"installation": "AVAILABLE",
|
|
15
|
+
"authentication": "ON_INSTALL"
|
|
16
|
+
},
|
|
17
|
+
"category": "Productivity"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
package/README.md
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
claude-smart
|
|
7
7
|
</h1>
|
|
8
8
|
|
|
9
|
-
<h4 align="center">
|
|
9
|
+
<h4 align="center">A local learning plugin for <a href="https://claude.com/claude-code" target="_blank">Claude Code</a> and Codex that turns corrections into durable rules your coding assistant follows in future sessions.</h4>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="LICENSE">
|
|
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.24-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">
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg" alt="Node">
|
|
23
23
|
</a>
|
|
24
24
|
<a href="#quick-start">
|
|
25
|
-
<img src="https://img.shields.io/badge/
|
|
25
|
+
<img src="https://img.shields.io/badge/hosts-Claude%20Code%20%2B%20Codex-purple.svg" alt="Hosts">
|
|
26
26
|
</a>
|
|
27
27
|
<a href="https://discord.gg/Jbft3jPn">
|
|
28
28
|
<img src="https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white" alt="Discord">
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<p align="center">
|
|
33
33
|
<a href="#quick-start">Quick Start</a> •
|
|
34
34
|
<a href="#how-it-works">How It Works</a> •
|
|
35
|
-
<a href="#
|
|
35
|
+
<a href="#commands">Commands</a> •
|
|
36
36
|
<a href="#dashboard">Dashboard</a> •
|
|
37
37
|
<a href="#configuration">Configuration</a> •
|
|
38
38
|
<a href="TROUBLESHOOTING.md">Troubleshooting</a> •
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
</p>
|
|
41
41
|
|
|
42
42
|
<p align="center">
|
|
43
|
-
It learns both corrections and successful execution patterns—so
|
|
43
|
+
It learns both corrections and successful execution patterns—so your coding assistant avoids repeating mistakes and reuses what works. Project-specific skills capture repo-local rules, and shared skills roll up durable patterns for reuse across projects.
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
<p align="center">
|
|
@@ -55,7 +55,7 @@ Most memory solutions are still mostly informative—Claude remembers what happe
|
|
|
55
55
|
|
|
56
56
|
`claude-smart` focuses on learning instead.
|
|
57
57
|
|
|
58
|
-
Four ways this changes what
|
|
58
|
+
Four ways this changes what your coding assistant can do for you:
|
|
59
59
|
|
|
60
60
|
- 💡 **Stop repeating the same mistakes:** Produces actionable skills Claude can follow next time; memory only records what happened.
|
|
61
61
|
|
|
@@ -78,6 +78,8 @@ Four ways this changes what Claude Code can do for you:
|
|
|
78
78
|
|
|
79
79
|
## Quick Start
|
|
80
80
|
|
|
81
|
+
### Claude Code
|
|
82
|
+
|
|
81
83
|
```bash
|
|
82
84
|
claude plugin marketplace add ReflexioAI/claude-smart
|
|
83
85
|
claude plugin install claude-smart@reflexioai
|
|
@@ -108,10 +110,45 @@ Or, if you already have Node.js or uv:
|
|
|
108
110
|
npx claude-smart uninstall # or: uvx claude-smart uninstall
|
|
109
111
|
```
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
### Codex
|
|
114
|
+
|
|
115
|
+
You need the `codex` CLI on `PATH` and Node.js available for `npx`:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx claude-smart install --host codex
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The helper registers the bundled **ReflexioAI** marketplace with Codex and
|
|
122
|
+
enables Codex plugin hooks. Then:
|
|
123
|
+
|
|
124
|
+
1. Fully quit and reopen Codex in your project.
|
|
125
|
+
2. Run `/plugins`.
|
|
126
|
+
3. Install `claude-smart` from the **ReflexioAI** marketplace.
|
|
127
|
+
4. Restart Codex again so hooks reload.
|
|
128
|
+
|
|
129
|
+
Do not create a `~/plugins/claude-smart` symlink for a normal `npx` install;
|
|
130
|
+
that symlink is only for plugin development from a cloned checkout.
|
|
131
|
+
|
|
132
|
+
Installing from a clone is only for plugin development; see
|
|
133
|
+
[DEVELOPER.md](./DEVELOPER.md#developing-locally).
|
|
134
|
+
|
|
135
|
+
Codex and Claude Code intentionally share the same `CLAUDE_SMART_*` environment
|
|
136
|
+
variables, `~/.reflexio/` data, `~/.claude-smart/` session buffers, backend,
|
|
137
|
+
dashboard, and learned skills/preferences.
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
To uninstall:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx claude-smart uninstall --host codex
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This removes the Codex marketplace registration, installed plugin config, and
|
|
147
|
+
Codex plugin cache. Local data under `~/.reflexio/` and `~/.claude-smart/` is
|
|
148
|
+
left in place — remove manually if desired. Restart Codex after uninstalling.
|
|
112
149
|
|
|
113
150
|
Developing the plugin itself? See [DEVELOPER.md](./DEVELOPER.md#developing-locally).
|
|
114
|
-
> **Not supported:** Claude Code Cowork
|
|
151
|
+
> **Not supported:** Claude Code Cowork, claude.ai/code web, or remote Codex environments without local plugin hooks — they run outside your local machine, so the local backend/dashboard and `~/.reflexio/` aren't reachable.
|
|
115
152
|
|
|
116
153
|
---
|
|
117
154
|
|
|
@@ -124,13 +161,13 @@ Developing the plugin itself? See [DEVELOPER.md](./DEVELOPER.md#developing-local
|
|
|
124
161
|
- 🔌 **No external API call** — semantic search runs on an in-process ONNX embedder (all-MiniLM-L6-v2), and all data (preferences, skills, interaction buffers) is stored locally on your machine (`~/.reflexio/` and `~/.claude-smart/`).
|
|
125
162
|
- 🔎 **Hybrid search** — Skills and preferences are indexed with vector + BM25 search for fast, robust retrieval.
|
|
126
163
|
- 🧪 **Offline resilience** — If the reflexio backend is down, hooks buffer to disk; the next successful publish drains them.
|
|
127
|
-
- 🧰 **Manual correction marker** — `/claude-smart:learn` flags the last turn as a correction so the extractor weights it heavily.
|
|
164
|
+
- 🧰 **Manual correction marker** — `/claude-smart:learn` in Claude Code, or `bash ~/.reflexio/plugin-root/scripts/cli.sh learn` in Codex, flags the last turn as a correction so the extractor weights it heavily.
|
|
128
165
|
|
|
129
166
|
---
|
|
130
167
|
|
|
131
168
|
## Dashboard
|
|
132
169
|
|
|
133
|
-
A web UI for browsing session histories, inspecting preferences, and editing project-specific and shared skills. The dashboard auto-starts alongside the backend, so you can open **http://localhost:3001** directly. Or run `/claude-smart:dashboard` in Claude Code to launch dashboard in browser.
|
|
170
|
+
A web UI for browsing session histories, inspecting preferences, and editing project-specific and shared skills. The dashboard auto-starts alongside the backend, so you can open **http://localhost:3001** directly. Or run `/claude-smart:dashboard` in Claude Code to launch dashboard in browser. In Codex, run `bash ~/.reflexio/plugin-root/scripts/dashboard-open.sh`.
|
|
134
171
|
|
|
135
172
|
<p align="center">
|
|
136
173
|
<img src="assets/preferences_dashboard.png" alt="Preferences dashboard" width="49%">
|
|
@@ -141,7 +178,7 @@ A web UI for browsing session histories, inspecting preferences, and editing pro
|
|
|
141
178
|
|
|
142
179
|
## How It Works
|
|
143
180
|
|
|
144
|
-
claude-smart builds three artifacts as you work and injects the relevant ones into Claude:
|
|
181
|
+
claude-smart builds three artifacts as you work and injects the relevant ones into Claude Code or Codex:
|
|
145
182
|
|
|
146
183
|
- **Preferences** (project-scoped) — how you work in this specific repo (stack, role, small quirks). *e.g.* "uses pnpm, not npm"; "prefers terse answers"; "backend engineer — explain frontend with backend analogues."
|
|
147
184
|
- **Project-specific skills** — durable rules with triggers and rationales learned from corrections in a project. *e.g.* "always pass `--run` to `npm test` — watch mode hangs CI."
|
|
@@ -149,32 +186,35 @@ claude-smart builds three artifacts as you work and injects the relevant ones in
|
|
|
149
186
|
|
|
150
187
|
Skills clean themselves up: correct the same thing twice and they merge; change your mind and the old one is archived.
|
|
151
188
|
|
|
152
|
-
Under the hood: hooks watch your turns, tool calls, and
|
|
189
|
+
Under the hood: hooks watch your turns, tool calls, and assistant replies, auto-flagging corrections (or anything you flag with `/learn`). At session end (or on `/learn`), [reflexio](https://github.com/ReflexioAI/reflexio) — the self-improving engine that powers claude-smart — extracts preferences and project-specific skills, then rolls durable patterns into shared skills. On each new user prompt, claude-smart searches for matching context and injects only the relevant hits. Run `/show` or the equivalent CLI command to audit the current learned state. Everything runs on your machine.
|
|
153
190
|
|
|
154
|
-
**Citations
|
|
191
|
+
**Citations.** At the end of a reply, the assistant may append a short marker:
|
|
155
192
|
|
|
156
193
|
```
|
|
157
|
-
|
|
158
|
-
⎿ (No output)
|
|
159
|
-
|
|
160
|
-
⏺ ✨ 2 claude-smart learnings applied
|
|
194
|
+
✨ 2 claude-smart learnings applied [cs:s1-252,p1-5aed]
|
|
161
195
|
```
|
|
162
196
|
|
|
163
|
-
That signals a preference (`p…`) or skill (`s…`) materially shaped the reply.
|
|
197
|
+
That signals a preference (`p…`) or skill (`s…`) materially shaped the reply.
|
|
198
|
+
Standalone wrappers like `✨abc123✨` are not claude-smart citations and will not
|
|
199
|
+
link back to dashboard entries. Open the interaction's detail page in the
|
|
200
|
+
[dashboard](#dashboard) to see the exact cited item.
|
|
164
201
|
|
|
165
202
|
See [ARCHITECTURE.md](./ARCHITECTURE.md) for hooks, data flow, and reflexio details.
|
|
166
203
|
|
|
167
204
|
---
|
|
168
205
|
|
|
169
|
-
##
|
|
206
|
+
## Commands
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
|
175
|
-
|
|
|
176
|
-
| `/
|
|
177
|
-
| `/
|
|
208
|
+
Claude Code installs these as slash commands. In Codex, run the equivalent shell
|
|
209
|
+
command directly, or ask Codex to run it.
|
|
210
|
+
|
|
211
|
+
| Claude Code | Codex / shell | What it does |
|
|
212
|
+
| --- | --- | --- |
|
|
213
|
+
| `/dashboard` | `bash ~/.reflexio/plugin-root/scripts/dashboard-open.sh` | Open the dashboard in your browser, auto-starting the reflexio backend and dashboard services if they aren't already running. |
|
|
214
|
+
| `/show` | `bash ~/.reflexio/plugin-root/scripts/cli.sh show` | Print current project-specific skills, shared skills, and the current project's preferences so you can audit learned state manually. |
|
|
215
|
+
| `/learn [note]` | `bash ~/.reflexio/plugin-root/scripts/cli.sh learn --note "optional note"` | Flag the most recent turn as a correction (for cases the automatic heuristic missed) and force reflexio to run extraction *now* on the session's unpublished interactions. The optional note becomes the correction description the extractor sees. |
|
|
216
|
+
| `/restart` | `bash ~/.reflexio/plugin-root/scripts/cli.sh restart` | Restart the reflexio backend and dashboard to pick up new changes (e.g. after upgrading the plugin or editing local reflexio code). |
|
|
217
|
+
| `/clear-all` | `bash ~/.reflexio/plugin-root/scripts/cli.sh clear-all --yes` | **Destructive.** Delete *all* reflexio interactions, preferences, and skills. Use when you want to wipe learned state and start fresh. |
|
|
178
218
|
|
|
179
219
|
---
|
|
180
220
|
|
|
@@ -189,6 +229,8 @@ Advanced users can tune claude-smart via environment variables — see [DEVELOPE
|
|
|
189
229
|
| `~/.reflexio/data/reflexio.db` | Source of truth for learned preferences, skills, interactions, full-text indexes, and embedding tables (plus `.db-shm` / `.db-wal` WAL sidecars). Inspect with `sqlite3`. |
|
|
190
230
|
| `~/.reflexio/.env` | Provider config — `CLAUDE_SMART_USE_LOCAL_CLI`, `CLAUDE_SMART_USE_LOCAL_EMBEDDING`, any optional API keys. |
|
|
191
231
|
| `.claude/settings.local.json` or `~/.claude/settings.json` | Claude Code hook environment, such as `CLAUDE_SMART_ENABLE_OPTIMIZER`; use project-local settings for one repo or user settings for all projects. |
|
|
232
|
+
| `~/.codex/config.toml` | Codex feature flags, including `plugin_hooks = true` after `claude-smart install --host codex`. |
|
|
233
|
+
| `~/.codex/plugins/cache/reflexioai/claude-smart/<version>/` | Codex's cached install of the `claude-smart` plugin from the `ReflexioAI` marketplace. |
|
|
192
234
|
| `~/.reflexio/plugin-root` | Self-healed symlink to the active plugin dir (managed by `ensure-plugin-root.sh` — written on install, refreshed each `SessionStart`). Slash commands resolve through it, so don't delete it; if you do, the next session will recreate it. |
|
|
193
235
|
| `~/.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. |
|
|
194
236
|
| `~/.cache/chroma/onnx_models/all-MiniLM-L6-v2/` | Cached ONNX weights (~86 MB, downloaded once). Delete to force a re-download. |
|
|
@@ -211,4 +253,4 @@ See the [LICENSE](LICENSE) file for details.
|
|
|
211
253
|
|
|
212
254
|
---
|
|
213
255
|
|
|
214
|
-
**Built on** [reflexio](https://github.com/ReflexioAI/reflexio) · **Runs on** [Claude Code](https://claude.com/claude-code) · **Written in** Python 3.12+
|
|
256
|
+
**Built on** [reflexio](https://github.com/ReflexioAI/reflexio) · **Runs on** [Claude Code](https://claude.com/claude-code) and Codex · **Written in** Python 3.12+
|
package/bin/claude-smart.js
CHANGED
|
@@ -1,22 +1,75 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* npx claude-smart install — thin wrapper around the native
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* npx claude-smart install — thin wrapper around the native host plugin
|
|
4
|
+
* CLIs. For Claude Code it registers the GitHub marketplace and installs the
|
|
5
|
+
* plugin. For Codex it copies the bundled local marketplace, registers it,
|
|
6
|
+
* and enables plugin hooks. Both paths seed ~/.reflexio/.env with the two
|
|
7
|
+
* local-provider flags so reflexio can route generation through local tools
|
|
8
|
+
* with no API key.
|
|
7
9
|
*
|
|
8
10
|
* Keep this file dependency-free — it runs via `npx` with no install step.
|
|
9
11
|
*/
|
|
10
12
|
"use strict";
|
|
11
13
|
|
|
12
|
-
const {
|
|
13
|
-
const {
|
|
14
|
+
const { execSync, spawn } = require("child_process");
|
|
15
|
+
const {
|
|
16
|
+
appendFileSync,
|
|
17
|
+
cpSync,
|
|
18
|
+
existsSync,
|
|
19
|
+
mkdirSync,
|
|
20
|
+
readFileSync,
|
|
21
|
+
rmSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
} = require("fs");
|
|
14
24
|
const { homedir } = require("os");
|
|
15
25
|
const { dirname, join } = require("path");
|
|
16
26
|
|
|
17
27
|
const DEFAULT_MARKETPLACE_SOURCE = "ReflexioAI/claude-smart";
|
|
18
28
|
const PLUGIN_SPEC = "claude-smart@reflexioai";
|
|
29
|
+
const CODEX_MARKETPLACE_NAME = "reflexioai";
|
|
30
|
+
const CODEX_MARKETPLACE_DISPLAY_NAME = "ReflexioAI";
|
|
31
|
+
const CODEX_PLUGIN_ID = `claude-smart@${CODEX_MARKETPLACE_NAME}`;
|
|
19
32
|
const REFLEXIO_ENV_PATH = join(homedir(), ".reflexio", ".env");
|
|
33
|
+
const CODEX_CONFIG_PATH = join(homedir(), ".codex", "config.toml");
|
|
34
|
+
const PACKAGE_ROOT = dirname(dirname(__filename));
|
|
35
|
+
const CODEX_MARKETPLACE_DIR = join(
|
|
36
|
+
homedir(),
|
|
37
|
+
".claude",
|
|
38
|
+
"plugins",
|
|
39
|
+
"marketplaces",
|
|
40
|
+
CODEX_MARKETPLACE_NAME,
|
|
41
|
+
);
|
|
42
|
+
const CODEX_MARKETPLACE_PLUGIN_PATH = join("plugins", "claude-smart");
|
|
43
|
+
const CODEX_PLUGIN_CACHE_DIR = join(
|
|
44
|
+
homedir(),
|
|
45
|
+
".codex",
|
|
46
|
+
"plugins",
|
|
47
|
+
"cache",
|
|
48
|
+
CODEX_MARKETPLACE_NAME,
|
|
49
|
+
"claude-smart",
|
|
50
|
+
);
|
|
51
|
+
const CODEX_REQUIRED_FILES = [
|
|
52
|
+
".agents/plugins/marketplace.json",
|
|
53
|
+
"plugin/.codex-plugin/plugin.json",
|
|
54
|
+
"plugin/hooks/codex-hooks.json",
|
|
55
|
+
"plugin/scripts/_codex_env.sh",
|
|
56
|
+
];
|
|
57
|
+
const CODEX_CLI_TIMEOUT_MS = 30_000;
|
|
58
|
+
const COPYTREE_IGNORE_NAMES = new Set([
|
|
59
|
+
"__pycache__",
|
|
60
|
+
".venv",
|
|
61
|
+
".pytest_cache",
|
|
62
|
+
".ruff_cache",
|
|
63
|
+
"node_modules",
|
|
64
|
+
".next",
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
function shouldCopyPath(src) {
|
|
68
|
+
const base = src.split(/[\\/]/).pop() || "";
|
|
69
|
+
if (COPYTREE_IGNORE_NAMES.has(base)) return false;
|
|
70
|
+
if (base.endsWith(".pyc") || base.endsWith(".pyo")) return false;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
20
73
|
|
|
21
74
|
function runClaude(args, { spinnerLabel } = {}) {
|
|
22
75
|
const useSpinner = Boolean(spinnerLabel) && process.stdout.isTTY && !process.env.CI;
|
|
@@ -80,7 +133,11 @@ function runClaude(args, { spinnerLabel } = {}) {
|
|
|
80
133
|
}
|
|
81
134
|
|
|
82
135
|
function hasClaudeCli() {
|
|
83
|
-
|
|
136
|
+
return hasCli("claude");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function hasCli(name) {
|
|
140
|
+
const probe = process.platform === "win32" ? `where ${name}` : `command -v ${name}`;
|
|
84
141
|
try {
|
|
85
142
|
execSync(probe, { stdio: "ignore" });
|
|
86
143
|
return true;
|
|
@@ -89,6 +146,30 @@ function hasClaudeCli() {
|
|
|
89
146
|
}
|
|
90
147
|
}
|
|
91
148
|
|
|
149
|
+
function runCodex(args) {
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
const child = spawn("codex", args, {
|
|
152
|
+
stdio: "inherit",
|
|
153
|
+
timeout: CODEX_CLI_TIMEOUT_MS,
|
|
154
|
+
killSignal: "SIGTERM",
|
|
155
|
+
});
|
|
156
|
+
let timedOut = false;
|
|
157
|
+
child.on("exit", (code, signal) => {
|
|
158
|
+
if (signal === "SIGTERM" && code === null) {
|
|
159
|
+
timedOut = true;
|
|
160
|
+
process.stderr.write(
|
|
161
|
+
`error: codex ${args.join(" ")} timed out after ${CODEX_CLI_TIMEOUT_MS / 1000}s\n`,
|
|
162
|
+
);
|
|
163
|
+
resolve(124);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (timedOut) return;
|
|
167
|
+
resolve(typeof code === "number" ? code : 1);
|
|
168
|
+
});
|
|
169
|
+
child.on("error", () => resolve(1));
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
92
173
|
function seedReflexioEnv() {
|
|
93
174
|
mkdirSync(dirname(REFLEXIO_ENV_PATH), { recursive: true });
|
|
94
175
|
const existing = existsSync(REFLEXIO_ENV_PATH)
|
|
@@ -106,19 +187,27 @@ function seedReflexioEnv() {
|
|
|
106
187
|
function printHelp() {
|
|
107
188
|
process.stdout.write(
|
|
108
189
|
[
|
|
109
|
-
"claude-smart — install helper for
|
|
190
|
+
"claude-smart — install helper for Claude Code and Codex",
|
|
110
191
|
"",
|
|
111
192
|
"Usage:",
|
|
112
193
|
" npx claude-smart install Install the plugin into Claude Code",
|
|
194
|
+
" npx claude-smart install --host codex Register the plugin marketplace for Codex",
|
|
113
195
|
" npx claude-smart install --source <owner/repo> Override the marketplace source",
|
|
196
|
+
" npx claude-smart uninstall --host codex Remove the Codex marketplace registration",
|
|
114
197
|
" npx claude-smart --help Show this help",
|
|
115
198
|
"",
|
|
116
|
-
"
|
|
199
|
+
"Claude Code install:",
|
|
117
200
|
" 1. claude plugin marketplace add <source>",
|
|
118
201
|
` 2. claude plugin install ${PLUGIN_SPEC}`,
|
|
119
202
|
" 3. Appends CLAUDE_SMART_USE_LOCAL_CLI=1 and CLAUDE_SMART_USE_LOCAL_EMBEDDING=1",
|
|
120
203
|
" to ~/.reflexio/.env (idempotent).",
|
|
121
204
|
"",
|
|
205
|
+
"Codex install:",
|
|
206
|
+
` 1. Copies the bundled marketplace to ${CODEX_MARKETPLACE_DIR}`,
|
|
207
|
+
" 2. codex plugin marketplace add <copied marketplace>",
|
|
208
|
+
" 3. codex features enable plugin_hooks",
|
|
209
|
+
" 4. Fully quit and reopen Codex, run /plugins, install claude-smart, then restart Codex.",
|
|
210
|
+
"",
|
|
122
211
|
"Update:",
|
|
123
212
|
" npx claude-smart update Update to the latest version",
|
|
124
213
|
"",
|
|
@@ -140,6 +229,121 @@ function parseSource(args) {
|
|
|
140
229
|
return value;
|
|
141
230
|
}
|
|
142
231
|
|
|
232
|
+
function parseHost(args) {
|
|
233
|
+
const idx = args.indexOf("--host");
|
|
234
|
+
if (idx === -1) return "claude-code";
|
|
235
|
+
const value = args[idx + 1];
|
|
236
|
+
if (!value) {
|
|
237
|
+
process.stderr.write("error: --host requires a value: claude-code or codex\n");
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
if (value !== "claude-code" && value !== "codex") {
|
|
241
|
+
process.stderr.write("error: --host must be claude-code or codex\n");
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
return value;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function copyCodexMarketplace() {
|
|
248
|
+
for (const rel of CODEX_REQUIRED_FILES) {
|
|
249
|
+
const path = join(PACKAGE_ROOT, rel);
|
|
250
|
+
if (!existsSync(path)) {
|
|
251
|
+
process.stderr.write(
|
|
252
|
+
`error: published package is missing ${rel}; reinstall claude-smart or use a newer release\n`,
|
|
253
|
+
);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
rmSync(CODEX_MARKETPLACE_DIR, { recursive: true, force: true });
|
|
259
|
+
mkdirSync(join(CODEX_MARKETPLACE_DIR, ".agents", "plugins"), { recursive: true });
|
|
260
|
+
mkdirSync(join(CODEX_MARKETPLACE_DIR, "plugins"), { recursive: true });
|
|
261
|
+
|
|
262
|
+
writeFileSync(
|
|
263
|
+
join(CODEX_MARKETPLACE_DIR, ".agents", "plugins", "marketplace.json"),
|
|
264
|
+
JSON.stringify(
|
|
265
|
+
{
|
|
266
|
+
name: CODEX_MARKETPLACE_NAME,
|
|
267
|
+
interface: { displayName: CODEX_MARKETPLACE_DISPLAY_NAME },
|
|
268
|
+
plugins: [
|
|
269
|
+
{
|
|
270
|
+
name: "claude-smart",
|
|
271
|
+
source: {
|
|
272
|
+
source: "local",
|
|
273
|
+
path: `./${CODEX_MARKETPLACE_PLUGIN_PATH}`,
|
|
274
|
+
},
|
|
275
|
+
policy: {
|
|
276
|
+
installation: "AVAILABLE",
|
|
277
|
+
authentication: "ON_INSTALL",
|
|
278
|
+
},
|
|
279
|
+
category: "Productivity",
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
null,
|
|
284
|
+
2,
|
|
285
|
+
) + "\n",
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
cpSync(join(PACKAGE_ROOT, "plugin"), join(CODEX_MARKETPLACE_DIR, CODEX_MARKETPLACE_PLUGIN_PATH), {
|
|
289
|
+
recursive: true,
|
|
290
|
+
force: true,
|
|
291
|
+
verbatimSymlinks: false,
|
|
292
|
+
filter: shouldCopyPath,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
for (const rel of ["README.md", "LICENSE", "package.json"]) {
|
|
296
|
+
const src = join(PACKAGE_ROOT, rel);
|
|
297
|
+
if (existsSync(src)) {
|
|
298
|
+
cpSync(src, join(CODEX_MARKETPLACE_DIR, rel), {
|
|
299
|
+
recursive: true,
|
|
300
|
+
force: true,
|
|
301
|
+
verbatimSymlinks: false,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return CODEX_MARKETPLACE_DIR;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function removeTomlSections(path, { exact, prefixes = [] }) {
|
|
309
|
+
if (!existsSync(path)) return true;
|
|
310
|
+
const text = readFileSync(path, "utf8");
|
|
311
|
+
if (!text) return true;
|
|
312
|
+
|
|
313
|
+
let changed = false;
|
|
314
|
+
let dropping = false;
|
|
315
|
+
const lines = text.split(/(?<=\n)/);
|
|
316
|
+
const kept = [];
|
|
317
|
+
for (const line of lines) {
|
|
318
|
+
const match = line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/);
|
|
319
|
+
if (match) {
|
|
320
|
+
const name = match[1].trim();
|
|
321
|
+
dropping = exact.has(name) || prefixes.some((prefix) => name.startsWith(prefix));
|
|
322
|
+
changed = changed || dropping;
|
|
323
|
+
}
|
|
324
|
+
if (!dropping) kept.push(line);
|
|
325
|
+
}
|
|
326
|
+
if (changed) writeFileSync(path, kept.join(""));
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function cleanupCodexInstallState() {
|
|
331
|
+
removeTomlSections(CODEX_CONFIG_PATH, {
|
|
332
|
+
exact: new Set([
|
|
333
|
+
`plugins."${CODEX_PLUGIN_ID}"`,
|
|
334
|
+
`marketplaces.${CODEX_MARKETPLACE_NAME}`,
|
|
335
|
+
]),
|
|
336
|
+
prefixes: [`hooks.state."${CODEX_PLUGIN_ID}:`],
|
|
337
|
+
});
|
|
338
|
+
rmSync(CODEX_MARKETPLACE_DIR, { recursive: true, force: true });
|
|
339
|
+
rmSync(CODEX_PLUGIN_CACHE_DIR, { recursive: true, force: true });
|
|
340
|
+
try {
|
|
341
|
+
rmSync(dirname(CODEX_PLUGIN_CACHE_DIR), { recursive: false, force: true });
|
|
342
|
+
} catch {
|
|
343
|
+
// Leave the marketplace cache parent if Codex has other entries there.
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
143
347
|
async function runUpdate() {
|
|
144
348
|
if (!hasClaudeCli()) {
|
|
145
349
|
process.stderr.write(
|
|
@@ -160,7 +364,12 @@ async function runUpdate() {
|
|
|
160
364
|
process.stdout.write("\nclaude-smart updated. Restart Claude Code to apply.\n");
|
|
161
365
|
}
|
|
162
366
|
|
|
163
|
-
async function runUninstall() {
|
|
367
|
+
async function runUninstall(args) {
|
|
368
|
+
if (parseHost(args) === "codex") {
|
|
369
|
+
await runUninstallCodex();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
164
373
|
if (!hasClaudeCli()) {
|
|
165
374
|
process.stderr.write(
|
|
166
375
|
"error: 'claude' CLI not found on PATH. " +
|
|
@@ -190,6 +399,11 @@ async function runUninstall() {
|
|
|
190
399
|
}
|
|
191
400
|
|
|
192
401
|
async function runInstall(args) {
|
|
402
|
+
if (parseHost(args) === "codex") {
|
|
403
|
+
await runInstallCodex();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
193
407
|
if (!hasClaudeCli()) {
|
|
194
408
|
process.stderr.write(
|
|
195
409
|
"error: 'claude' CLI not found on PATH. " +
|
|
@@ -232,6 +446,77 @@ async function runInstall(args) {
|
|
|
232
446
|
);
|
|
233
447
|
}
|
|
234
448
|
|
|
449
|
+
async function runInstallCodex() {
|
|
450
|
+
if (!hasCli("codex")) {
|
|
451
|
+
process.stderr.write("error: 'codex' CLI not found on PATH. Install Codex first.\n");
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const marketplaceRoot = copyCodexMarketplace();
|
|
456
|
+
process.stdout.write(`Prepared Codex marketplace at ${marketplaceRoot}.\n`);
|
|
457
|
+
|
|
458
|
+
let code = await runCodex(["plugin", "marketplace", "add", marketplaceRoot]);
|
|
459
|
+
if (code !== 0) {
|
|
460
|
+
process.stderr.write(
|
|
461
|
+
`warning: \`codex plugin marketplace add ${marketplaceRoot}\` failed; retrying after removing ${CODEX_MARKETPLACE_NAME}.\n`,
|
|
462
|
+
);
|
|
463
|
+
await runCodex(["plugin", "marketplace", "remove", CODEX_MARKETPLACE_NAME]);
|
|
464
|
+
code = await runCodex(["plugin", "marketplace", "add", marketplaceRoot]);
|
|
465
|
+
}
|
|
466
|
+
if (code !== 0) {
|
|
467
|
+
process.stderr.write(
|
|
468
|
+
`error: could not register Codex marketplace. Run manually: codex plugin marketplace add ${marketplaceRoot}\n`,
|
|
469
|
+
);
|
|
470
|
+
process.exit(code);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
code = await runCodex(["features", "enable", "plugin_hooks"]);
|
|
474
|
+
if (code !== 0) {
|
|
475
|
+
process.stderr.write("error: could not enable Codex plugin_hooks feature.\n");
|
|
476
|
+
process.exit(code);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const added = seedReflexioEnv();
|
|
480
|
+
if (added.length > 0) {
|
|
481
|
+
process.stdout.write(`Seeded ${REFLEXIO_ENV_PATH} with ${added.join(", ")}.\n`);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
process.stdout.write(
|
|
485
|
+
[
|
|
486
|
+
"",
|
|
487
|
+
"claude-smart Codex support is prepared.",
|
|
488
|
+
`Fully quit and reopen Codex, run /plugins, install claude-smart from the ${CODEX_MARKETPLACE_DISPLAY_NAME} marketplace, then restart Codex so hooks reload.`,
|
|
489
|
+
"Local data is shared with Claude Code under ~/.reflexio/ and ~/.claude-smart/.",
|
|
490
|
+
"",
|
|
491
|
+
].join("\n"),
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
async function runUninstallCodex() {
|
|
496
|
+
if (!hasCli("codex")) {
|
|
497
|
+
process.stdout.write("Codex CLI not found; skipping marketplace removal.\n");
|
|
498
|
+
cleanupCodexInstallState();
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const code = await runCodex(["plugin", "marketplace", "remove", CODEX_MARKETPLACE_NAME]);
|
|
503
|
+
if (code !== 0) {
|
|
504
|
+
process.stderr.write(
|
|
505
|
+
`warning: Codex marketplace removal failed; remove manually with: codex plugin marketplace remove ${CODEX_MARKETPLACE_NAME}\n`,
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
cleanupCodexInstallState();
|
|
509
|
+
|
|
510
|
+
process.stdout.write(
|
|
511
|
+
[
|
|
512
|
+
"",
|
|
513
|
+
"claude-smart Codex plugin and marketplace state removed. Restart Codex to apply.",
|
|
514
|
+
"Codex's global plugin_hooks feature and local data under ~/.reflexio/ and ~/.claude-smart/ were left in place.",
|
|
515
|
+
"",
|
|
516
|
+
].join("\n"),
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
|
|
235
520
|
async function main() {
|
|
236
521
|
const args = process.argv.slice(2);
|
|
237
522
|
const cmd = args[0] || "install";
|
|
@@ -252,7 +537,7 @@ async function main() {
|
|
|
252
537
|
}
|
|
253
538
|
|
|
254
539
|
if (cmd === "uninstall") {
|
|
255
|
-
await runUninstall();
|
|
540
|
+
await runUninstall(args.slice(1));
|
|
256
541
|
return;
|
|
257
542
|
}
|
|
258
543
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-smart",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.24",
|
|
4
4
|
"description": "Self-improving Claude Code plugin — learns from corrections via reflexio",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -27,6 +27,16 @@
|
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"bin",
|
|
30
|
+
".agents/plugins/marketplace.json",
|
|
31
|
+
"plugin",
|
|
32
|
+
"!plugin/**/__pycache__",
|
|
33
|
+
"!plugin/**/*.py[cod]",
|
|
34
|
+
"!plugin/**/.pytest_cache",
|
|
35
|
+
"!plugin/**/.ruff_cache",
|
|
36
|
+
"!plugin/**/.mypy_cache",
|
|
37
|
+
"!plugin/**/.venv",
|
|
38
|
+
"!plugin/**/node_modules",
|
|
39
|
+
"!plugin/**/.next/cache",
|
|
30
40
|
"README.md",
|
|
31
41
|
"LICENSE"
|
|
32
42
|
],
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-smart",
|
|
3
|
+
"version": "0.2.24",
|
|
4
|
+
"description": "Self-improving Claude Code plugin — learns from corrections across sessions via reflexio",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Yi Lu"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"claude",
|
|
10
|
+
"claude-code",
|
|
11
|
+
"plugin",
|
|
12
|
+
"reflexio",
|
|
13
|
+
"self-improvement",
|
|
14
|
+
"playbook",
|
|
15
|
+
"learning"
|
|
16
|
+
]
|
|
17
|
+
}
|