claude-smart 0.2.43 → 0.2.45
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 +3 -3
- package/README.md +1 -1
- package/bin/claude-smart.js +2 -2
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/README.md +21 -1
- package/plugin/pyproject.toml +3 -3
- package/plugin/scripts/_lib.sh +72 -28
- package/plugin/scripts/backend-service.sh +55 -7
- package/plugin/scripts/cli.sh +2 -1
- package/plugin/scripts/dashboard-service.sh +7 -5
- package/plugin/scripts/ensure-plugin-root.sh +1 -0
- package/plugin/scripts/hook_entry.sh +7 -5
- package/plugin/scripts/smart-install.sh +2 -2
- package/plugin/src/README.md +57 -0
- package/plugin/uv.lock +126 -5
- package/plugin/vendor/reflexio/.env.example +9 -0
- package/plugin/vendor/reflexio/pyproject.toml +5 -2
- package/plugin/vendor/reflexio/reflexio/cli/bootstrap_config.py +0 -1
- package/plugin/vendor/reflexio/reflexio/cli/commands/setup_cmd.py +7 -4
- package/plugin/vendor/reflexio/reflexio/cli/env_loader.py +4 -4
- package/plugin/vendor/reflexio/reflexio/lib/_storage_labels.py +2 -2
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +13 -4
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +3 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/validators.py +59 -6
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/README.md +7 -1
- package/plugin/vendor/reflexio/reflexio/server/api.py +188 -34
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/README.md +34 -0
- package/plugin/vendor/reflexio/reflexio/server/api_endpoints/publisher_api.py +33 -11
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +278 -29
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +457 -181
- package/plugin/vendor/reflexio/reflexio/server/llm/llm_utils.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +22 -12
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +137 -9
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +36 -3
- package/plugin/vendor/reflexio/reflexio/server/llm/rerank/cross_encoder_reranker.py +13 -3
- package/plugin/vendor/reflexio/reflexio/server/llm/tools.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.1.prompt.md +69 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.2.prompt.md +71 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.0.prompt.md +27 -23
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.2.prompt.md +234 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context/v4.2.3.prompt.md +244 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_extraction_context_expert/v3.3.0.prompt.md +19 -9
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +58 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/group_evaluation_runner.py +1 -5
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +44 -2
- package/plugin/vendor/reflexio/reflexio/server/services/embedding_text.py +62 -0
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/pending_tool_call_dispatch.py +8 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +91 -24
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +3 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_config_utils.py +6 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extractor_interaction_utils.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +18 -5
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +2 -2
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_consolidator.py +88 -3
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_deduplicator.py +36 -5
- package/plugin/vendor/reflexio/reflexio/server/services/profile/profile_generation_service.py +6 -3
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/reflection_service.py +6 -3
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/relevance_floor.py +32 -22
- package/plugin/vendor/reflexio/reflexio/server/services/service_utils.py +89 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_agent_run.py +46 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_agent_run.py +12 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +8 -4
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"name": "Yi Lu"
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
|
-
"description": "claude-smart — self-improving Claude Code and Codex plugin
|
|
7
|
+
"description": "claude-smart — self-improving Claude Code and Codex plugin powered by Reflexio"
|
|
8
8
|
},
|
|
9
9
|
"plugins": [
|
|
10
10
|
{
|
|
11
11
|
"name": "claude-smart",
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.45",
|
|
13
13
|
"source": "./plugin",
|
|
14
|
-
"description": "Turns
|
|
14
|
+
"description": "Turns corrections into Preferences, Project-specific skills, and Shared skills — uses Claude Code or Codex as the LLM backend (no external API key required)"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
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.45-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">
|
package/bin/claude-smart.js
CHANGED
|
@@ -905,7 +905,7 @@ async function installVendoredReflexio(pluginRoot, uv, env) {
|
|
|
905
905
|
process.stdout.write(`Installing bundled Reflexio source from ${vendorRoot}...\n`);
|
|
906
906
|
let code = await runChecked(
|
|
907
907
|
uv,
|
|
908
|
-
["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--quiet", "-
|
|
908
|
+
["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--quiet", "--reinstall", "--no-deps", vendorRoot],
|
|
909
909
|
{ cwd: pluginRoot, env },
|
|
910
910
|
);
|
|
911
911
|
if (code !== 0) {
|
|
@@ -914,7 +914,7 @@ async function installVendoredReflexio(pluginRoot, uv, env) {
|
|
|
914
914
|
);
|
|
915
915
|
code = await runChecked(
|
|
916
916
|
uv,
|
|
917
|
-
["pip", "install", "--project", pluginRoot, "--python", pythonPath, "-
|
|
917
|
+
["pip", "install", "--project", pluginRoot, "--python", pythonPath, "--reinstall", "--no-deps", vendorRoot],
|
|
918
918
|
{ cwd: pluginRoot, env },
|
|
919
919
|
);
|
|
920
920
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-smart",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Self-improving Claude Code and Codex plugin
|
|
3
|
+
"version": "0.2.45",
|
|
4
|
+
"description": "Self-improving Claude Code and Codex plugin that turns corrections into Preferences, Project-specific skills, and Shared skills",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
7
7
|
"claude-code",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-smart",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Self-improving Claude Code and Codex plugin
|
|
3
|
+
"version": "0.2.45",
|
|
4
|
+
"description": "Self-improving Claude Code and Codex plugin that turns corrections into Preferences, Project-specific skills, and Shared skills",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Yi Lu"
|
|
7
7
|
},
|
package/plugin/README.md
CHANGED
|
@@ -6,6 +6,8 @@ This directory is the published Python package (`claude-smart` on PyPI) and the
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
+
### Claude Code
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
12
|
claude plugin marketplace add ReflexioAI/claude-smart
|
|
11
13
|
claude plugin install claude-smart@reflexioai
|
|
@@ -25,8 +27,19 @@ embedding/ML dependency stack does not provide a complete native wheel set.
|
|
|
25
27
|
|
|
26
28
|
Then restart Claude Code.
|
|
27
29
|
|
|
30
|
+
### Codex
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx claude-smart install --host codex
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then fully quit and reopen Codex so hooks reload. Codex installs reuse the same
|
|
37
|
+
local Preferences, Project-specific skills, and Shared skills as Claude Code.
|
|
38
|
+
|
|
28
39
|
## Uninstall
|
|
29
40
|
|
|
41
|
+
### Claude Code
|
|
42
|
+
|
|
30
43
|
```bash
|
|
31
44
|
claude plugin uninstall claude-smart@reflexioai
|
|
32
45
|
```
|
|
@@ -37,7 +50,14 @@ Or, if Node.js or uv is already installed:
|
|
|
37
50
|
npx claude-smart uninstall # or: uvx claude-smart uninstall
|
|
38
51
|
```
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
### Codex
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx claude-smart uninstall --host codex
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Restart Codex after uninstalling. Local data under `~/.reflexio/` and
|
|
60
|
+
`~/.claude-smart/` is left in place for both hosts — remove manually if desired.
|
|
41
61
|
|
|
42
62
|
## License
|
|
43
63
|
|
package/plugin/pyproject.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-smart"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "Self-improving Claude Code and Codex plugin
|
|
3
|
+
version = "0.2.45"
|
|
4
|
+
description = "Self-improving Claude Code and Codex plugin that turns corrections into Preferences, Project-specific skills, and Shared skills"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
dependencies = [
|
|
@@ -9,7 +9,7 @@ dependencies = [
|
|
|
9
9
|
# normal installs; vendor releases may override it after uv sync by
|
|
10
10
|
# installing plugin/vendor/reflexio. Keep in sync via
|
|
11
11
|
# scripts/sync-reflexio-dep.py.
|
|
12
|
-
"reflexio-ai>=0.2.
|
|
12
|
+
"reflexio-ai>=0.2.25",
|
|
13
13
|
# Needed when Reflexio runs the local embedding provider (ONNXMiniLM_L6_V2).
|
|
14
14
|
# Pulls in onnxruntime + tokenizers; the ~80 MB ONNX model itself is
|
|
15
15
|
# downloaded on first use, not at install time.
|
package/plugin/scripts/_lib.sh
CHANGED
|
@@ -3,11 +3,53 @@
|
|
|
3
3
|
# Claude Code hooks run with a minimal non-interactive PATH that often omits
|
|
4
4
|
# nvm/asdf/brew shims where `npm`, `uv`, etc. live. Pull the user's login-shell
|
|
5
5
|
# PATH the same way claude-mem does so hook-spawned scripts find them without
|
|
6
|
-
# the user having to mutate their global PATH. Best-effort
|
|
6
|
+
# the user having to mutate their global PATH. Best-effort and bounded: shell
|
|
7
|
+
# profile startup can be slow or stuck on Windows, so this must never outlive a
|
|
8
|
+
# hook's timeout budget.
|
|
9
|
+
claude_smart_login_path_timeout_seconds() {
|
|
10
|
+
local _VALUE
|
|
11
|
+
_VALUE="${CLAUDE_SMART_LOGIN_PATH_TIMEOUT_SECONDS:-2}"
|
|
12
|
+
case "$_VALUE" in
|
|
13
|
+
''|*[!0-9]*) printf '%s\n' "2" ;;
|
|
14
|
+
*) printf '%s\n' "$_VALUE" ;;
|
|
15
|
+
esac
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
claude_smart_capture_login_path() {
|
|
19
|
+
local _TIMEOUT _TMP _PID _WAITED _LINE
|
|
20
|
+
_TIMEOUT="$(claude_smart_login_path_timeout_seconds)"
|
|
21
|
+
[ "$_TIMEOUT" -gt 0 ] || return 1
|
|
22
|
+
|
|
23
|
+
_TMP="${TMPDIR:-/tmp}/claude-smart-login-path.$$"
|
|
24
|
+
rm -f "$_TMP" 2>/dev/null || true
|
|
25
|
+
"$SHELL" -lc 'printf %s "$PATH"' >"$_TMP" 2>/dev/null &
|
|
26
|
+
_PID=$!
|
|
27
|
+
_WAITED=0
|
|
28
|
+
while kill -0 "$_PID" 2>/dev/null; do
|
|
29
|
+
if [ "$_WAITED" -ge "$_TIMEOUT" ]; then
|
|
30
|
+
kill "$_PID" 2>/dev/null || true
|
|
31
|
+
wait "$_PID" 2>/dev/null || true
|
|
32
|
+
rm -f "$_TMP" 2>/dev/null || true
|
|
33
|
+
return 1
|
|
34
|
+
fi
|
|
35
|
+
sleep 1
|
|
36
|
+
_WAITED=$((_WAITED + 1))
|
|
37
|
+
done
|
|
38
|
+
if wait "$_PID" 2>/dev/null; then
|
|
39
|
+
while IFS= read -r _LINE || [ -n "$_LINE" ]; do
|
|
40
|
+
printf '%s' "$_LINE"
|
|
41
|
+
done <"$_TMP"
|
|
42
|
+
rm -f "$_TMP" 2>/dev/null || true
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
rm -f "$_TMP" 2>/dev/null || true
|
|
46
|
+
return 1
|
|
47
|
+
}
|
|
48
|
+
|
|
7
49
|
claude_smart_source_login_path() {
|
|
8
50
|
local _SHELL_PATH
|
|
9
51
|
if [ -n "${SHELL:-}" ] && [ -x "$SHELL" ]; then
|
|
10
|
-
if _SHELL_PATH="$(
|
|
52
|
+
if _SHELL_PATH="$(claude_smart_capture_login_path)"; then
|
|
11
53
|
[ -n "$_SHELL_PATH" ] && export PATH="$_SHELL_PATH:$PATH"
|
|
12
54
|
fi
|
|
13
55
|
fi
|
|
@@ -116,30 +158,24 @@ claude_smart_dashboard_unavailable_marker() {
|
|
|
116
158
|
}
|
|
117
159
|
|
|
118
160
|
claude_smart_node_recovery_hint() {
|
|
119
|
-
|
|
120
|
-
Recovery:
|
|
121
|
-
1. Restart Claude Code to let claude-smart retry its private Node.js install.
|
|
122
|
-
2. If the retry is blocked by your network or OS policy, install Node.js 20.9+ manually:
|
|
123
|
-
EOF
|
|
161
|
+
printf '%s\n' \
|
|
162
|
+
"Recovery:" \
|
|
163
|
+
" 1. Restart Claude Code to let claude-smart retry its private Node.js install." \
|
|
164
|
+
" 2. If the retry is blocked by your network or OS policy, install Node.js 20.9+ manually:"
|
|
124
165
|
if claude_smart_is_windows; then
|
|
125
|
-
|
|
126
|
-
- winget install OpenJS.NodeJS.LTS
|
|
127
|
-
- or download the LTS installer from https://nodejs.org/
|
|
128
|
-
EOF
|
|
166
|
+
printf '%s\n' \
|
|
167
|
+
" - winget install OpenJS.NodeJS.LTS" \
|
|
168
|
+
" - or download the LTS installer from https://nodejs.org/"
|
|
129
169
|
elif [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then
|
|
130
|
-
|
|
131
|
-
- brew install node
|
|
132
|
-
- or download the LTS installer from https://nodejs.org/
|
|
133
|
-
EOF
|
|
170
|
+
printf '%s\n' \
|
|
171
|
+
" - brew install node" \
|
|
172
|
+
" - or download the LTS installer from https://nodejs.org/"
|
|
134
173
|
else
|
|
135
|
-
|
|
136
|
-
- use your distro package manager for nodejs/npm
|
|
137
|
-
- or download the LTS archive from https://nodejs.org/
|
|
138
|
-
EOF
|
|
174
|
+
printf '%s\n' \
|
|
175
|
+
" - use your distro package manager for nodejs/npm" \
|
|
176
|
+
" - or download the LTS archive from https://nodejs.org/"
|
|
139
177
|
fi
|
|
140
|
-
|
|
141
|
-
3. Run /claude-smart:restart, then /claude-smart:dashboard.
|
|
142
|
-
EOF
|
|
178
|
+
printf '%s\n' " 3. Run /claude-smart:restart, then /claude-smart:dashboard."
|
|
143
179
|
}
|
|
144
180
|
|
|
145
181
|
claude_smart_write_dashboard_unavailable() {
|
|
@@ -527,14 +563,22 @@ claude_smart_append_capped_log() {
|
|
|
527
563
|
# POSIX: setsid → python3 os.setsid → nohup (in that order of strength).
|
|
528
564
|
# Windows: nohup alone — Git Bash has no setsid, no process groups, and
|
|
529
565
|
# `os.setsid()` is POSIX-only; nohup ignores SIGHUP which is enough to
|
|
530
|
-
# survive the parent console closing.
|
|
531
|
-
#
|
|
532
|
-
#
|
|
533
|
-
#
|
|
534
|
-
#
|
|
566
|
+
# survive the parent console closing. On Windows, stdout/stderr are also
|
|
567
|
+
# closed here so hook-runner pipes cannot be kept alive by long-lived
|
|
568
|
+
# background children after the hook script exits unless the caller explicitly
|
|
569
|
+
# opts into preserving stdout/stderr for a file redirection. The python3
|
|
570
|
+
# fallback is gated on a real-interpreter probe (-V) so the Windows App
|
|
571
|
+
# Execution Alias stub doesn't get invoked. POSIX callers are responsible for
|
|
572
|
+
# redirecting stdout/stderr; we do not impose a log destination there. Stdin is
|
|
573
|
+
# closed so the child cannot inherit a tty. Use `$!` after this call to capture
|
|
574
|
+
# the pid.
|
|
535
575
|
claude_smart_spawn_detached() {
|
|
536
576
|
if claude_smart_is_windows; then
|
|
537
|
-
|
|
577
|
+
if [ "${CLAUDE_SMART_SPAWN_KEEP_OUTPUT:-}" = "1" ]; then
|
|
578
|
+
nohup "$@" < /dev/null &
|
|
579
|
+
else
|
|
580
|
+
nohup "$@" < /dev/null > /dev/null 2>&1 &
|
|
581
|
+
fi
|
|
538
582
|
return 0
|
|
539
583
|
fi
|
|
540
584
|
if command -v setsid >/dev/null 2>&1; then
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Subcommands:
|
|
7
7
|
# start probe /health; if nothing we recognize is on the port,
|
|
8
|
-
# spawn
|
|
9
|
-
# --no-reload` detached. Polls /health briefly so first
|
|
8
|
+
# spawn the prepared venv's `reflexio services start --only
|
|
9
|
+
# backend --no-reload` detached. Polls /health briefly so first
|
|
10
10
|
# use after session start lands on a warm server, then
|
|
11
11
|
# returns a continue payload regardless.
|
|
12
12
|
# stop SIGTERM the recorded process group, escalating to
|
|
@@ -20,11 +20,13 @@ set -eu
|
|
|
20
20
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
21
21
|
# shellcheck source=_lib.sh
|
|
22
22
|
. "$HERE/_lib.sh"
|
|
23
|
-
|
|
23
|
+
CMD="${1:-start}"
|
|
24
|
+
if [ "$CMD" != "session-end" ]; then
|
|
25
|
+
claude_smart_source_login_path
|
|
26
|
+
fi
|
|
24
27
|
claude_smart_prepend_astral_bins
|
|
25
28
|
claude_smart_source_reflexio_env
|
|
26
29
|
|
|
27
|
-
CMD="${1:-start}"
|
|
28
30
|
PORT=8071
|
|
29
31
|
EMBEDDING_PORT="${EMBEDDING_PORT:-8072}"
|
|
30
32
|
# Pass through to `reflexio services start/stop` so the spawned backend
|
|
@@ -183,6 +185,35 @@ port_holder() {
|
|
|
183
185
|
| awk 'NR==2 {print $1" (pid "$2")"; exit}'
|
|
184
186
|
}
|
|
185
187
|
|
|
188
|
+
ensure_vendored_reflexio_active() {
|
|
189
|
+
vendor="$PLUGIN_ROOT/vendor/reflexio"
|
|
190
|
+
[ -f "$vendor/pyproject.toml" ] || return 0
|
|
191
|
+
plugin_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")"
|
|
192
|
+
[ -x "$plugin_python" ] || return 0
|
|
193
|
+
if "$plugin_python" - "$vendor/pyproject.toml" <<'PY' >/dev/null 2>&1; then
|
|
194
|
+
import importlib.metadata
|
|
195
|
+
import re
|
|
196
|
+
import sys
|
|
197
|
+
from pathlib import Path
|
|
198
|
+
|
|
199
|
+
text = Path(sys.argv[1]).read_text(encoding="utf-8")
|
|
200
|
+
match = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
|
|
201
|
+
if not match:
|
|
202
|
+
raise SystemExit(1)
|
|
203
|
+
expected = match.group(1)
|
|
204
|
+
try:
|
|
205
|
+
installed = importlib.metadata.version("reflexio-ai")
|
|
206
|
+
except importlib.metadata.PackageNotFoundError:
|
|
207
|
+
raise SystemExit(1)
|
|
208
|
+
raise SystemExit(0 if installed == expected else 1)
|
|
209
|
+
PY
|
|
210
|
+
return 0
|
|
211
|
+
fi
|
|
212
|
+
claude_smart_append_capped_log "$LOG_FILE" "$LOG_MAX_BYTES" \
|
|
213
|
+
"[claude-smart] backend: repairing vendored Reflexio install before start"
|
|
214
|
+
uv pip install --project "$PLUGIN_ROOT" --python "$plugin_python" --quiet --reinstall --no-deps "$vendor" >&2
|
|
215
|
+
}
|
|
216
|
+
|
|
186
217
|
# Full shutdown: kill the recorded process group (if any) then sweep
|
|
187
218
|
# both the backend port and the embedding-service port for surviving
|
|
188
219
|
# reflexio listeners. Used by both `stop` and the opt-in `session-end`
|
|
@@ -233,7 +264,7 @@ case "$CMD" in
|
|
|
233
264
|
if ! command -v uv >/dev/null 2>&1; then
|
|
234
265
|
if [ "${CLAUDE_SMART_BOOTSTRAPPING:-}" != "1" ] && [ -x "$PLUGIN_ROOT/scripts/smart-install.sh" ]; then
|
|
235
266
|
claude_smart_append_capped_log "$LOG_FILE" "$LOG_MAX_BYTES" "[claude-smart] backend: uv not on PATH; starting installer in background"
|
|
236
|
-
claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
267
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
237
268
|
bash "$PLUGIN_ROOT/scripts/smart-install.sh" \
|
|
238
269
|
>>"$STATE_DIR/install.log" 2>&1 || true
|
|
239
270
|
fi
|
|
@@ -243,6 +274,7 @@ case "$CMD" in
|
|
|
243
274
|
fi
|
|
244
275
|
fi
|
|
245
276
|
cd "$PLUGIN_ROOT"
|
|
277
|
+
ensure_vendored_reflexio_active
|
|
246
278
|
|
|
247
279
|
# Cap local interaction history to keep the SQLite store small for
|
|
248
280
|
# claude-smart users. Reflexio's library defaults are much higher
|
|
@@ -266,6 +298,21 @@ case "$CMD" in
|
|
|
266
298
|
# without touching the file on disk.
|
|
267
299
|
export REFLEXIO_STORAGE="sqlite"
|
|
268
300
|
|
|
301
|
+
backend_pythonpath="${PYTHONPATH:-}"
|
|
302
|
+
if [ -d "$PLUGIN_ROOT/vendor/reflexio/reflexio" ]; then
|
|
303
|
+
vendor_pythonpath="$PLUGIN_ROOT/vendor/reflexio"
|
|
304
|
+
pythonpath_sep=":"
|
|
305
|
+
if claude_smart_is_windows; then
|
|
306
|
+
# Native Windows Python expects ;-separated Windows-style paths in
|
|
307
|
+
# PYTHONPATH; MSYS does not auto-convert arbitrary env vars.
|
|
308
|
+
pythonpath_sep=";"
|
|
309
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
310
|
+
vendor_pythonpath="$(cygpath -w "$vendor_pythonpath")"
|
|
311
|
+
fi
|
|
312
|
+
fi
|
|
313
|
+
backend_pythonpath="$vendor_pythonpath${backend_pythonpath:+$pythonpath_sep$backend_pythonpath}"
|
|
314
|
+
fi
|
|
315
|
+
|
|
269
316
|
# (nohup; no process groups). backend-log-runner.sh owns stdout/stderr
|
|
270
317
|
# capture so process output cannot grow backend.log past its cap.
|
|
271
318
|
#
|
|
@@ -277,11 +324,12 @@ case "$CMD" in
|
|
|
277
324
|
# CLAUDE_SMART_BACKEND_WORKERS for power users running concurrent
|
|
278
325
|
# Claude Code sessions or wanting zero-downtime recycling.
|
|
279
326
|
workers="${CLAUDE_SMART_BACKEND_WORKERS:-1}"
|
|
327
|
+
backend_python="$(claude_smart_plugin_python "$PLUGIN_ROOT")"
|
|
280
328
|
claude_smart_spawn_detached bash "$HERE/backend-log-runner.sh" \
|
|
281
329
|
"$LOG_FILE" "$LOG_MAX_BYTES" -- \
|
|
282
330
|
env PYTHONIOENCODING="${PYTHONIOENCODING:-utf-8}" \
|
|
283
|
-
|
|
284
|
-
reflexio services start --only backend --no-reload --workers "$workers"
|
|
331
|
+
PYTHONPATH="$backend_pythonpath" \
|
|
332
|
+
"$backend_python" -m reflexio.cli services start --only backend --no-reload --workers "$workers"
|
|
285
333
|
svc_pid=$!
|
|
286
334
|
# Record the spawned pid, not a pgid sampled with ps. On POSIX,
|
|
287
335
|
# setsid/python os.setsid make this pid the new process group leader;
|
package/plugin/scripts/cli.sh
CHANGED
|
@@ -91,4 +91,5 @@ if ! claude_smart_python_imports "$PLUGIN_ROOT" claude_smart.cli; then
|
|
|
91
91
|
fi
|
|
92
92
|
fi
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
PLUGIN_PYTHON="$(claude_smart_plugin_python "$PLUGIN_ROOT")"
|
|
95
|
+
exec "$PLUGIN_PYTHON" -m claude_smart.cli "$@"
|
|
@@ -21,11 +21,13 @@ set -eu
|
|
|
21
21
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
22
22
|
# shellcheck source=_lib.sh
|
|
23
23
|
. "$HERE/_lib.sh"
|
|
24
|
-
|
|
24
|
+
CMD="${1:-start}"
|
|
25
|
+
if [ "$CMD" != "session-end" ]; then
|
|
26
|
+
claude_smart_source_login_path
|
|
27
|
+
fi
|
|
25
28
|
claude_smart_prepend_node_bins
|
|
26
29
|
claude_smart_source_reflexio_env
|
|
27
30
|
|
|
28
|
-
CMD="${1:-start}"
|
|
29
31
|
PORT=3001
|
|
30
32
|
|
|
31
33
|
PLUGIN_ROOT="$(cd "$HERE/.." && pwd)"
|
|
@@ -192,7 +194,7 @@ case "$CMD" in
|
|
|
192
194
|
if [ -z "$NPM_BIN" ] || ! "$NPM_BIN" --version >/dev/null 2>&1; then
|
|
193
195
|
if [ "${CLAUDE_SMART_BOOTSTRAPPING:-}" != "1" ] && [ -x "$PLUGIN_ROOT/scripts/smart-install.sh" ]; then
|
|
194
196
|
echo "[claude-smart] dashboard: npm is not on PATH; starting installer in background" >>"$LOG_FILE"
|
|
195
|
-
claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
197
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
196
198
|
bash "$PLUGIN_ROOT/scripts/smart-install.sh" \
|
|
197
199
|
>>"$STATE_DIR/install.log" 2>&1 || true
|
|
198
200
|
fi
|
|
@@ -214,7 +216,7 @@ case "$CMD" in
|
|
|
214
216
|
BUILD_PID_FILE="$STATE_DIR/dashboard-build.pid"
|
|
215
217
|
if ! claude_smart_pid_alive_file "$BUILD_PID_FILE"; then
|
|
216
218
|
echo "[claude-smart] dashboard: .next missing — starting background build (~1-2 min)" >>"$LOG_FILE"
|
|
217
|
-
claude_smart_spawn_detached bash "$HERE/dashboard-build.sh" >>"$LOG_FILE" 2>&1
|
|
219
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached bash "$HERE/dashboard-build.sh" >>"$LOG_FILE" 2>&1
|
|
218
220
|
fi
|
|
219
221
|
emit_ok; exit 0
|
|
220
222
|
fi
|
|
@@ -229,7 +231,7 @@ case "$CMD" in
|
|
|
229
231
|
# Caller-side `>>file 2>&1` redirection is honoured before the child
|
|
230
232
|
# detaches, so per-OS log paths stay identical.
|
|
231
233
|
export CLAUDE_SMART_DASHBOARD_WORKSPACE="$WORKSPACE_CWD"
|
|
232
|
-
claude_smart_spawn_detached "$NPM_BIN" run start >>"$LOG_FILE" 2>&1
|
|
234
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached "$NPM_BIN" run start >>"$LOG_FILE" 2>&1
|
|
233
235
|
dash_pid=$!
|
|
234
236
|
# Record the spawned pid, not a pgid sampled with ps. On POSIX,
|
|
235
237
|
# setsid/python os.setsid make this pid the new process group leader;
|
|
@@ -20,6 +20,7 @@ if [ ! -f "$TARGET/pyproject.toml" ]; then
|
|
|
20
20
|
echo "[claude-smart] ensure-plugin-root: $TARGET is not a plugin dir (no pyproject.toml)" >&2
|
|
21
21
|
exit 1
|
|
22
22
|
fi
|
|
23
|
+
TARGET="$(cd "$TARGET" && pwd -P)"
|
|
23
24
|
|
|
24
25
|
LINK="$HOME/.reflexio/plugin-root"
|
|
25
26
|
mkdir -p "$(dirname "$LINK")"
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
# CLAUDE_PLUGIN_ROOT points at the plugin dir (dev: <repo>/plugin;
|
|
4
4
|
# installed: ~/.claude/plugins/cache/reflexioai/claude-smart/<version>),
|
|
5
5
|
# which is also the Python project root with pyproject.toml + uv.lock.
|
|
6
|
-
# We invoke
|
|
7
|
-
#
|
|
6
|
+
# We invoke the prepared venv Python directly so hooks use the dependency set
|
|
7
|
+
# produced by smart-install.sh, including the vendored Reflexio snapshot it
|
|
8
|
+
# installs non-editably (--reinstall --no-deps).
|
|
8
9
|
#
|
|
9
10
|
# If the Setup hook recorded an install failure at
|
|
10
11
|
# ~/.claude-smart/install-failed, short-circuit with a user-visible
|
|
@@ -95,7 +96,7 @@ if ! command -v uv >/dev/null 2>&1; then
|
|
|
95
96
|
fi
|
|
96
97
|
if [ -x "$PLUGIN_ROOT/scripts/smart-install.sh" ]; then
|
|
97
98
|
mkdir -p "$STATE_DIR"
|
|
98
|
-
claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
99
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
99
100
|
bash "$PLUGIN_ROOT/scripts/smart-install.sh" \
|
|
100
101
|
>>"$STATE_DIR/install.log" 2>&1 || true
|
|
101
102
|
fi
|
|
@@ -122,7 +123,7 @@ ensure_hook_package_importable() {
|
|
|
122
123
|
printf '%s\n' "[claude-smart] hook: claude_smart.hook is not importable; retrying install in background"
|
|
123
124
|
date 2>/dev/null || true
|
|
124
125
|
} >>"$STATE_DIR/install.log" 2>&1
|
|
125
|
-
claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
126
|
+
CLAUDE_SMART_SPAWN_KEEP_OUTPUT=1 claude_smart_spawn_detached env CLAUDE_SMART_BOOTSTRAPPING=1 \
|
|
126
127
|
bash "$PLUGIN_ROOT/scripts/smart-install.sh" \
|
|
127
128
|
>>"$STATE_DIR/install.log" 2>&1 || true
|
|
128
129
|
|
|
@@ -135,4 +136,5 @@ if ! ensure_hook_package_importable; then
|
|
|
135
136
|
fi
|
|
136
137
|
|
|
137
138
|
# Stdin is the hook payload JSON — stream it through to the Python CLI.
|
|
138
|
-
|
|
139
|
+
PLUGIN_PYTHON="$(claude_smart_plugin_python "$PLUGIN_ROOT")"
|
|
140
|
+
exec "$PLUGIN_PYTHON" -m claude_smart.hook "$HOST" "$EVENT"
|
|
@@ -142,12 +142,12 @@ install_vendored_reflexio() {
|
|
|
142
142
|
fi
|
|
143
143
|
|
|
144
144
|
echo "[claude-smart] installing bundled Reflexio source from $VENDORED_REFLEXIO" >&2
|
|
145
|
-
if uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --quiet -
|
|
145
|
+
if uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --quiet --reinstall --no-deps "$VENDORED_REFLEXIO" >&2; then
|
|
146
146
|
return 0
|
|
147
147
|
fi
|
|
148
148
|
|
|
149
149
|
echo "[claude-smart] warning: quiet vendored Reflexio install failed in $PLUGIN_ROOT; retrying with full output." >&2
|
|
150
|
-
if ! uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" -
|
|
150
|
+
if ! uv pip install --project "$PLUGIN_ROOT" --python "$PLUGIN_PYTHON" --reinstall --no-deps "$VENDORED_REFLEXIO" >&2; then
|
|
151
151
|
write_failure "vendored Reflexio install failed in $PLUGIN_ROOT"
|
|
152
152
|
fi
|
|
153
153
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# claude_smart (plugin/src)
|
|
2
|
+
Description: Python package powering the claude-smart plugin — hook handlers that buffer Claude Code / Codex session activity, publish it to a local Reflexio backend, and inject the learned skills/preferences back into future sessions.
|
|
3
|
+
|
|
4
|
+
> User-facing install/usage docs live in [`../README.md`](../README.md). This is the code map for the `claude_smart` package.
|
|
5
|
+
|
|
6
|
+
## Main Entry Points
|
|
7
|
+
|
|
8
|
+
| File | Purpose |
|
|
9
|
+
|------|---------|
|
|
10
|
+
| `hook.py` | Hook dispatcher. Parses the stdin JSON payload and routes each event (Setup, SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SessionEnd) to its handler in `events/`. |
|
|
11
|
+
| `cli.py` | `claude-smart` CLI: `install`, `uninstall`, `show`, `learn`, `restart`, `dashboard`, `clear-all`. |
|
|
12
|
+
| `state.py` | Per-session JSONL buffer at `~/.claude-smart/sessions/{session_id}.jsonl`; high-water mark for idempotent publish retries. |
|
|
13
|
+
| `publish.py` | Drains the session buffer, calls the Reflexio adapter, and stamps the watermark. Used by Stop, SessionEnd, and `learn`. |
|
|
14
|
+
| `reflexio_adapter.py` | Thin wrapper over `reflexio.ReflexioClient` — isolates import failures, 5s HTTP timeout, injects/queries learnings, degrades gracefully when the backend is down. |
|
|
15
|
+
|
|
16
|
+
## Event Handlers (`events/`)
|
|
17
|
+
|
|
18
|
+
| Handler | Hook | Role |
|
|
19
|
+
|---------|------|------|
|
|
20
|
+
| `session_start.py` | SessionStart | Apply extraction defaults, render stall banner, push optimizer context. |
|
|
21
|
+
| `user_prompt.py` | UserPromptSubmit | Inject learned playbooks/preferences into context. |
|
|
22
|
+
| `pre_tool.py` | PreToolUse (Edit/Write/Bash/NotebookEdit) | Inject project-specific context before tool execution. |
|
|
23
|
+
| `post_tool.py` | PostToolUse | Buffer the tool invocation (name, input, response, duration) into session state. |
|
|
24
|
+
| `stop.py` | Stop | Publish unpublished interactions (force extraction if configured). |
|
|
25
|
+
| `session_end.py` | SessionEnd | Final publish + aggregation; optional backend/dashboard shutdown. |
|
|
26
|
+
|
|
27
|
+
## Supporting Modules
|
|
28
|
+
|
|
29
|
+
| File | Purpose |
|
|
30
|
+
|------|---------|
|
|
31
|
+
| `env_config.py` | Parses `~/.reflexio/.env` (`REFLEXIO_URL`, `REFLEXIO_API_KEY`, `CLAUDE_SMART_READ_ONLY`, local embedding/CLI flags). |
|
|
32
|
+
| `runtime.py` | Host detection (Claude Code vs Codex); shared agent version. |
|
|
33
|
+
| `ids.py` | Session / project ID generation and resolution. |
|
|
34
|
+
| `context_inject.py`, `context_format.py`, `query_compose.py`, `cs_cite.py` | Build search queries, format learned skills as markdown, inject into context, format citations. |
|
|
35
|
+
| `stall_banner.py` | User-facing message when the Reflexio provider hits an auth/billing stall. |
|
|
36
|
+
| `optimizer_assistant.py` | Claude-code CLI agent that extracts Reflexio optimization hints. |
|
|
37
|
+
| `hook_log.py`, `internal_call.py` | Structured JSON logging to `~/.claude-smart/hook.log`; detect internal/test invocations to skip learning. |
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
SessionStart -> bootstrap Reflexio backend (8071) + Next.js dashboard (3001)
|
|
43
|
+
PostToolUse -> state.py buffers each tool call to ~/.claude-smart/sessions/{id}.jsonl
|
|
44
|
+
Stop/SessionEnd -> publish.py -> reflexio_adapter -> Reflexio extracts playbooks + preferences
|
|
45
|
+
UserPromptSubmit / PreToolUse -> context_inject pulls relevant learnings back into context
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- **Dual-host** — the same package runs under Claude Code (native slash commands) and Codex (shell-script fallbacks in `../scripts/`); host shape is normalized in `runtime.py`.
|
|
49
|
+
- **Offline-resilient** — if Reflexio is unreachable, interactions stay buffered and drain on the next successful publish.
|
|
50
|
+
- **Hooks registered** in `../hooks/hooks.json` (Claude Code) and `../hooks/codex-hooks.json` (Codex), dispatched through `../scripts/hook_entry.sh`.
|
|
51
|
+
|
|
52
|
+
## Requirements / Problems to Avoid
|
|
53
|
+
|
|
54
|
+
- **All learned state is external to the repo** — sessions buffer under `~/.claude-smart/`, Reflexio state under `~/.reflexio/`. Don't write generated runtime artifacts inside the plugin root.
|
|
55
|
+
- **Backend lives at `http://localhost:8071`**, dashboard at `http://localhost:3001`; both are long-lived across sessions (no hard shutdown on SessionEnd by default).
|
|
56
|
+
- **`CLAUDE_SMART_READ_ONLY`** skips publishing entirely — respect it in any new publish path.
|
|
57
|
+
- **Keep handlers fast** — tool-use hooks run on a 10–15s timeout; heavy work belongs in the backend, not the hook.
|