claude-smart 0.2.35 → 0.2.37

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.
@@ -250,9 +250,8 @@ class Adapter:
250
250
  def fetch_user_playbooks(self, *, project_id: str, top_k: int = 10) -> list[Any]:
251
251
  """Fetch CURRENT user playbooks for ``project_id``.
252
252
 
253
- User playbooks are scoped by the resolved user id: local installs use
254
- the project name, while managed installs use ``REFLEXIO_USER_ID``.
255
- Filtering mirrors the publish path
253
+ User playbooks are scoped by the resolved project id. Filtering mirrors
254
+ the publish path
256
255
  (``publish_interaction(user_id=project_id, …)``).
257
256
 
258
257
  Args:
@@ -150,6 +150,15 @@ def append(session_id: str, record: dict[str, Any]) -> None:
150
150
  fh.write(line)
151
151
 
152
152
 
153
+ def mark_all_published(session_id: str) -> None:
154
+ """Advance the watermark over every currently buffered record.
155
+
156
+ Read-only mode still needs to retire any already-buffered interactions so
157
+ they cannot publish later if learning is re-enabled.
158
+ """
159
+ append(session_id, {"published_up_to": len(read_all(session_id))})
160
+
161
+
153
162
  def read_all(session_id: str) -> list[dict[str, Any]]:
154
163
  """Return every record in the buffer as a list of dicts. Missing file → []."""
155
164
  path = session_path(session_id)
package/plugin/uv.lock CHANGED
@@ -419,7 +419,7 @@ wheels = [
419
419
 
420
420
  [[package]]
421
421
  name = "claude-smart"
422
- version = "0.2.35"
422
+ version = "0.2.37"
423
423
  source = { editable = "." }
424
424
  dependencies = [
425
425
  { name = "chromadb" },
@@ -1179,11 +1179,11 @@ wheels = [
1179
1179
 
1180
1180
  [[package]]
1181
1181
  name = "json-repair"
1182
- version = "0.59.5"
1182
+ version = "0.59.10"
1183
1183
  source = { registry = "https://pypi.org/simple" }
1184
- sdist = { url = "https://files.pythonhosted.org/packages/b7/67/eba7fad54ff6f5cce6db4e01f596fc68156b5c7e864af0aa07ad48e880a1/json_repair-0.59.5.tar.gz", hash = "sha256:bb886ee054e99066be8a337b67a986b6a50d79be9a5ad37ae81966e698990784", size = 48632, upload-time = "2026-04-24T11:41:38.133Z" }
1184
+ sdist = { url = "https://files.pythonhosted.org/packages/d3/7c/e95bb03068572146eba37e8175c760f470ea0a6097310e16bbf2bc6e6457/json_repair-0.59.10.tar.gz", hash = "sha256:2e4b85537c752d8a513ea28fdad891e5ede32c83de745366b97f648b8c34ede7", size = 49133, upload-time = "2026-05-14T06:41:51.222Z" }
1185
1185
  wheels = [
1186
- { url = "https://files.pythonhosted.org/packages/3e/aa/0529dee460b745b93f6abc97b56b7527314c5167ba29ab7a5bd5c08de01f/json_repair-0.59.5-py3-none-any.whl", hash = "sha256:6869965bd1cc1aaaa04dc85865c26fbb76d9a2d83a20010f5eae2563b1567827", size = 47282, upload-time = "2026-04-24T11:41:36.653Z" },
1186
+ { url = "https://files.pythonhosted.org/packages/ee/87/49b20c6b81493d55c311f711ed87319d0fbad8bd0bbfbe36e52103af36bd/json_repair-0.59.10-py3-none-any.whl", hash = "sha256:5468fa3eaadcc9b4a5646776bc4176e2fe5f374b5848a15f468cce3b60e3db0e", size = 47742, upload-time = "2026-05-14T06:41:49.812Z" },
1187
1187
  ]
1188
1188
 
1189
1189
  [[package]]
@@ -1711,11 +1711,14 @@ wheels = [
1711
1711
 
1712
1712
  [[package]]
1713
1713
  name = "nvidia-cublas"
1714
- version = "13.1.0.3"
1714
+ version = "13.1.1.3"
1715
1715
  source = { registry = "https://pypi.org/simple" }
1716
+ dependencies = [
1717
+ { name = "nvidia-cuda-nvrtc" },
1718
+ ]
1716
1719
  wheels = [
1717
- { url = "https://files.pythonhosted.org/packages/e1/a5/fce49e2ae977e0ccc084e5adafceb4f0ac0c8333cb6863501618a7277f67/nvidia_cublas-13.1.0.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c86fc7f7ae36d7528288c5d88098edcb7b02c633d262e7ddbb86b0ad91be5df2", size = 542851226, upload-time = "2025-10-09T08:59:04.818Z" },
1718
- { url = "https://files.pythonhosted.org/packages/e7/44/423ac00af4dd95a5aeb27207e2c0d9b7118702149bf4704c3ddb55bb7429/nvidia_cublas-13.1.0.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:ee8722c1f0145ab246bccb9e452153b5e0515fd094c3678df50b2a0888b8b171", size = 423133236, upload-time = "2025-10-09T08:59:32.536Z" },
1720
+ { url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" },
1721
+ { url = "https://files.pythonhosted.org/packages/3b/cd/154ca20c38269e05eff77c1464e6c1da89f50a6390b565e9d82e06bc11e1/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:37936a16db8fe4ac1f065c2139360608a543a09275cb1a1af612e08cfa065436", size = 423138758, upload-time = "2026-04-08T18:46:58.655Z" },
1719
1722
  ]
1720
1723
 
1721
1724
  [[package]]
@@ -3016,7 +3019,7 @@ wheels = [
3016
3019
 
3017
3020
  [[package]]
3018
3021
  name = "sentence-transformers"
3019
- version = "5.4.1"
3022
+ version = "5.5.1"
3020
3023
  source = { registry = "https://pypi.org/simple" }
3021
3024
  dependencies = [
3022
3025
  { name = "huggingface-hub" },
@@ -3028,9 +3031,9 @@ dependencies = [
3028
3031
  { name = "transformers" },
3029
3032
  { name = "typing-extensions" },
3030
3033
  ]
3031
- sdist = { url = "https://files.pythonhosted.org/packages/4d/68/7f98c221940ce783b492ad6140384daf2e2918cd7175009d6a362c22b9ee/sentence_transformers-5.4.1.tar.gz", hash = "sha256:436bcb1182a0ff42a8fb2b1c43498a70d0a75b688d182f2cd0d1dd115af61ddc", size = 428910, upload-time = "2026-04-14T13:34:59.006Z" }
3034
+ sdist = { url = "https://files.pythonhosted.org/packages/cf/d4/7ef93157485e978c016f49da05363c1e4e7237beb5343b64b5631101f0f1/sentence_transformers-5.5.1.tar.gz", hash = "sha256:02b7740dfc60bdbbcb6061625f5d97a5c1a4e2d3baac5f9391b912bb5eae2290", size = 445161, upload-time = "2026-05-20T07:37:44.465Z" }
3032
3035
  wheels = [
3033
- { url = "https://files.pythonhosted.org/packages/c5/d9/3a9b6f2ccdedc9dc00fe37b2fc58f58f8efbff44565cf4bf39d8568bb13a/sentence_transformers-5.4.1-py3-none-any.whl", hash = "sha256:a6d640fc363849b63affb8e140e9d328feabab86f83d58ac3e16b1c28140b790", size = 571311, upload-time = "2026-04-14T13:34:57.731Z" },
3036
+ { url = "https://files.pythonhosted.org/packages/bf/03/ee99a6b030e7a2e056547729f8a4709dd93e13d9c6f07590f74c395c4017/sentence_transformers-5.5.1-py3-none-any.whl", hash = "sha256:4fe11d433badc5282d32f7fc08bc714216b7a5aca426f9df77a45a554756deb7", size = 588887, upload-time = "2026-05-20T07:37:43.004Z" },
3034
3037
  ]
3035
3038
 
3036
3039
  [[package]]
@@ -3281,7 +3284,7 @@ wheels = [
3281
3284
 
3282
3285
  [[package]]
3283
3286
  name = "transformers"
3284
- version = "5.7.0"
3287
+ version = "5.9.0"
3285
3288
  source = { registry = "https://pypi.org/simple" }
3286
3289
  dependencies = [
3287
3290
  { name = "huggingface-hub" },
@@ -3294,9 +3297,9 @@ dependencies = [
3294
3297
  { name = "tqdm" },
3295
3298
  { name = "typer" },
3296
3299
  ]
3297
- sdist = { url = "https://files.pythonhosted.org/packages/4d/fe/7e84d20ac7d4d5d14bac2eab5976088d86342959fc2c0da54b4c2fc99856/transformers-5.7.0.tar.gz", hash = "sha256:a9d35cf39804e3456c1f9bc1a79ad5ffa878640a61f51f66f71c97f4b4e2ce10", size = 8401287, upload-time = "2026-04-28T18:30:09.75Z" }
3300
+ sdist = { url = "https://files.pythonhosted.org/packages/51/58/7f843608f2e8421f86bb97060b54649be6239ec612b82bf9d41e65c26c00/transformers-5.9.0.tar.gz", hash = "sha256:25997cb8fa6053533171634b6162d7df54346530ec2aa9b42bb834e63668c842", size = 8642240, upload-time = "2026-05-20T14:50:49.278Z" }
3298
3301
  wheels = [
3299
- { url = "https://files.pythonhosted.org/packages/60/60/86a9fe3037bec221094e2acb680219ad88b77006edba42fc0407a577ca93/transformers-5.7.0-py3-none-any.whl", hash = "sha256:869660cd8fc92badc041f5551bf755a42f4b9558c93341bf3fa3eeed7065079c", size = 10474236, upload-time = "2026-04-28T18:30:05.655Z" },
3302
+ { url = "https://files.pythonhosted.org/packages/02/ca/2eaa5359f2ccb8c2e1656bc26305ad0cf438aa392ce4b29ae67a315c186e/transformers-5.9.0-py3-none-any.whl", hash = "sha256:1d19509bcff7028ebc6b277d71caa712e8353778463d38764237d14b42b52788", size = 10787648, upload-time = "2026-05-20T14:50:45.337Z" },
3300
3303
  ]
3301
3304
 
3302
3305
  [[package]]
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env bash
2
+ # Interactive setup for claude-smart's shared ~/.reflexio/.env.
3
+ #
4
+ # Plain installs stay local and do not need this script. Use this when a user
5
+ # wants managed Reflexio, read-only mode, global sharing, or to switch back to
6
+ # local mode after a managed setup.
7
+
8
+ set -euo pipefail
9
+
10
+ HERE="$(cd "$(dirname "$0")" && pwd)"
11
+ REPO_ROOT="$(cd "$HERE/.." && pwd)"
12
+ INSTALLER="$REPO_ROOT/bin/claude-smart.js"
13
+ REFLEXIO_ENV="${REFLEXIO_ENV_PATH:-$HOME/.reflexio/.env}"
14
+ MANAGED_REFLEXIO_URL="https://www.reflexio.ai/"
15
+ GLOBAL_USER_ID="global_user"
16
+
17
+ log() { printf '[claude-smart setup] %s\n' "$*" >&2; }
18
+
19
+ env_unquote() {
20
+ local value first last
21
+ value="$1"
22
+ first="${value%"${value#?}"}"
23
+ last="${value#"${value%?}"}"
24
+ if { [ "$first" = '"' ] && [ "$last" = '"' ]; } || { [ "$first" = "'" ] && [ "$last" = "'" ]; }; then
25
+ value="${value#?}"
26
+ value="${value%?}"
27
+ fi
28
+ printf '%s\n' "$value"
29
+ }
30
+
31
+ env_quote() {
32
+ printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
33
+ }
34
+
35
+ get_env_value() {
36
+ local key line raw_key value
37
+ key="$1"
38
+ [ -f "$REFLEXIO_ENV" ] || return 1
39
+ while IFS= read -r line || [ -n "$line" ]; do
40
+ line="${line#"${line%%[![:space:]]*}"}"
41
+ line="${line%"${line##*[![:space:]]}"}"
42
+ [ -n "$line" ] || continue
43
+ case "$line" in
44
+ \#*) continue ;;
45
+ export\ *) line="${line#export }" ;;
46
+ esac
47
+ raw_key="${line%%=*}"
48
+ [ "$raw_key" != "$line" ] || continue
49
+ raw_key="${raw_key%"${raw_key##*[![:space:]]}"}"
50
+ [ "$raw_key" = "$key" ] || continue
51
+ value="${line#*=}"
52
+ value="${value#"${value%%[![:space:]]*}"}"
53
+ value="${value%"${value##*[![:space:]]}"}"
54
+ env_unquote "$value"
55
+ return 0
56
+ done < "$REFLEXIO_ENV"
57
+ return 1
58
+ }
59
+
60
+ remove_env_keys() {
61
+ local tmp line key raw_key remove target
62
+ [ -f "$REFLEXIO_ENV" ] || return 0
63
+ tmp="$(mktemp "${REFLEXIO_ENV}.tmp.XXXXXX")"
64
+ while IFS= read -r line || [ -n "$line" ]; do
65
+ raw_key="$line"
66
+ raw_key="${raw_key#"${raw_key%%[![:space:]]*}"}"
67
+ case "$raw_key" in
68
+ export\ *) raw_key="${raw_key#export }" ;;
69
+ esac
70
+ key="${raw_key%%=*}"
71
+ key="${key%"${key##*[![:space:]]}"}"
72
+ remove=0
73
+ if [ "$key" != "$raw_key" ]; then
74
+ if [ "$#" -gt 0 ]; then
75
+ for target in "$@"; do
76
+ [ "$key" = "$target" ] && remove=1
77
+ done
78
+ else
79
+ case "$key" in
80
+ REFLEXIO_API_KEY|REFLEXIO_URL|REFLEXIO_USER_ID|CLAUDE_SMART_READ_ONLY)
81
+ remove=1
82
+ ;;
83
+ esac
84
+ fi
85
+ fi
86
+ [ "$remove" = "1" ] || printf '%s\n' "$line" >> "$tmp"
87
+ done < "$REFLEXIO_ENV"
88
+
89
+ if ! grep -q '[^[:space:]]' "$tmp"; then
90
+ rm -f "$tmp" "$REFLEXIO_ENV"
91
+ return 0
92
+ fi
93
+ mv "$tmp" "$REFLEXIO_ENV"
94
+ chmod 600 "$REFLEXIO_ENV"
95
+ }
96
+
97
+ append_env_value() {
98
+ local key value quoted
99
+ key="$1"
100
+ value="$2"
101
+ quoted="$(env_quote "$value")"
102
+ mkdir -p "$(dirname "$REFLEXIO_ENV")"
103
+ touch "$REFLEXIO_ENV"
104
+ chmod 600 "$REFLEXIO_ENV"
105
+ printf '%s="%s"\n' "$key" "$quoted" >> "$REFLEXIO_ENV"
106
+ chmod 600 "$REFLEXIO_ENV"
107
+ }
108
+
109
+ mask_secret() {
110
+ local value len suffix
111
+ value="$1"
112
+ len="${#value}"
113
+ if [ "$len" -eq 0 ]; then
114
+ printf '%s\n' ''
115
+ elif [ "$len" -le 4 ]; then
116
+ printf '****%s\n' "$value"
117
+ else
118
+ suffix="${value: -4}"
119
+ printf '****%s\n' "$suffix"
120
+ fi
121
+ }
122
+
123
+ prompt() {
124
+ local message default answer
125
+ message="$1"
126
+ default="$2"
127
+ if [ -n "$default" ]; then
128
+ printf '%s [%s]: ' "$message" "$default" >&2
129
+ else
130
+ printf '%s: ' "$message" >&2
131
+ fi
132
+ IFS= read -r answer
133
+ if [ -z "$answer" ]; then
134
+ answer="$default"
135
+ fi
136
+ printf '%s\n' "$answer"
137
+ }
138
+
139
+ prompt_api_key() {
140
+ local existing masked answer
141
+ existing="$1"
142
+ masked="$(mask_secret "$existing")"
143
+ while :; do
144
+ if [ -n "$existing" ]; then
145
+ printf 'Reflexio API key [%s; press Enter to keep]: ' "$masked" >&2
146
+ else
147
+ printf 'Reflexio API key: ' >&2
148
+ fi
149
+ if [ -t 0 ]; then
150
+ IFS= read -rs answer
151
+ printf '\n' >&2
152
+ else
153
+ IFS= read -r answer
154
+ fi
155
+ if [ -z "$answer" ] && [ -n "$existing" ]; then
156
+ answer="$existing"
157
+ fi
158
+ if [ -z "$answer" ]; then
159
+ log "API key is required for managed Reflexio."
160
+ continue
161
+ fi
162
+ case "$answer" in
163
+ *[[:space:]]*)
164
+ log "API key must not contain whitespace."
165
+ continue
166
+ ;;
167
+ esac
168
+ printf '%s\n' "$answer"
169
+ return 0
170
+ done
171
+ }
172
+
173
+ normalize_host() {
174
+ case "$1" in
175
+ 1|claude|claude-code|Claude*) printf 'claude-code\n' ;;
176
+ 2|codex|Codex*) printf 'codex\n' ;;
177
+ 3|both|Both*) printf 'both\n' ;;
178
+ *) return 1 ;;
179
+ esac
180
+ }
181
+
182
+ normalize_mode() {
183
+ case "$1" in
184
+ 1|local|Local*) printf 'local\n' ;;
185
+ 2|managed|remote|Remote*) printf 'managed\n' ;;
186
+ *) return 1 ;;
187
+ esac
188
+ }
189
+
190
+ normalize_yes_no() {
191
+ case "$1" in
192
+ y|Y|yes|Yes|YES|true|1) printf 'yes\n' ;;
193
+ n|N|no|No|NO|false|0) printf 'no\n' ;;
194
+ *) return 1 ;;
195
+ esac
196
+ }
197
+
198
+ normalize_scope() {
199
+ case "$1" in
200
+ 1|project|Project*) printf 'project\n' ;;
201
+ 2|global|Global*) printf 'global\n' ;;
202
+ *) return 1 ;;
203
+ esac
204
+ }
205
+
206
+ is_local_url() {
207
+ case "$1" in
208
+ http://localhost|http://localhost/|http://localhost:*|http://127.0.0.1|http://127.0.0.1/|http://127.0.0.1:*|http://0.0.0.0|http://0.0.0.0/|http://0.0.0.0:*)
209
+ return 0
210
+ ;;
211
+ *)
212
+ return 1
213
+ ;;
214
+ esac
215
+ }
216
+
217
+ prompt_normalized() {
218
+ local label default normalizer answer normalized
219
+ label="$1"
220
+ default="$2"
221
+ normalizer="$3"
222
+ while :; do
223
+ answer="$(prompt "$label" "$default")"
224
+ if normalized="$("$normalizer" "$answer")"; then
225
+ printf '%s\n' "$normalized"
226
+ return 0
227
+ fi
228
+ log "Invalid choice: $answer"
229
+ done
230
+ }
231
+
232
+ install_for_host() {
233
+ local host node_bin
234
+ host="$1"
235
+ if [ "${CLAUDE_SMART_SETUP_NO_INSTALL:-}" = "1" ]; then
236
+ log "skipping plugin install because CLAUDE_SMART_SETUP_NO_INSTALL=1"
237
+ return 0
238
+ fi
239
+ node_bin="${NODE:-node}"
240
+ if [ ! -f "$INSTALLER" ]; then
241
+ log "ERROR: installer not found at $INSTALLER"
242
+ exit 1
243
+ fi
244
+ case "$host" in
245
+ claude-code)
246
+ "$node_bin" "$INSTALLER" install
247
+ ;;
248
+ codex)
249
+ "$node_bin" "$INSTALLER" install --host codex
250
+ ;;
251
+ both)
252
+ "$node_bin" "$INSTALLER" install
253
+ "$node_bin" "$INSTALLER" install --host codex
254
+ ;;
255
+ esac
256
+ }
257
+
258
+ main() {
259
+ local existing_api_key existing_url existing_user_id existing_read_only
260
+ local default_mode default_read_only default_scope host mode api_key read_only scope
261
+ local managed_url managed_user_id
262
+
263
+ existing_api_key="$(get_env_value REFLEXIO_API_KEY || true)"
264
+ existing_url="$(get_env_value REFLEXIO_URL || true)"
265
+ existing_user_id="$(get_env_value REFLEXIO_USER_ID || true)"
266
+ existing_read_only="$(get_env_value CLAUDE_SMART_READ_ONLY || true)"
267
+
268
+ default_mode="local"
269
+ if [ -n "$existing_api_key" ] || [ -n "$existing_url" ]; then
270
+ default_mode="managed"
271
+ fi
272
+ default_read_only="no"
273
+ case "$existing_read_only" in
274
+ 1|true|yes|on) default_read_only="yes" ;;
275
+ esac
276
+ default_scope="project"
277
+ if [ -n "$existing_user_id" ]; then
278
+ default_scope="global"
279
+ fi
280
+
281
+ host="$(prompt_normalized "Host (1=Claude Code, 2=Codex, 3=both)" "claude-code" normalize_host)"
282
+ mode="$(prompt_normalized "Setup mode (1=local, 2=managed Reflexio)" "$default_mode" normalize_mode)"
283
+
284
+ if [ "$mode" = "local" ]; then
285
+ if [ -f "$REFLEXIO_ENV" ]; then
286
+ remove_env_keys
287
+ log "removed managed Reflexio settings from $REFLEXIO_ENV"
288
+ else
289
+ log "local mode selected; no $REFLEXIO_ENV exists, so no env file was created"
290
+ fi
291
+ install_for_host "$host"
292
+ return 0
293
+ fi
294
+
295
+ api_key="$(prompt_api_key "$existing_api_key")"
296
+ read_only="$(prompt_normalized "Read-only mode? (yes/no)" "$default_read_only" normalize_yes_no)"
297
+ scope="$(prompt_normalized "Sharing scope (1=project, 2=global)" "$default_scope" normalize_scope)"
298
+
299
+ managed_url="${existing_url:-$MANAGED_REFLEXIO_URL}"
300
+ if is_local_url "$managed_url"; then
301
+ managed_url="$MANAGED_REFLEXIO_URL"
302
+ fi
303
+ managed_user_id=""
304
+ if [ "$scope" = "global" ]; then
305
+ managed_user_id="${existing_user_id:-$GLOBAL_USER_ID}"
306
+ fi
307
+
308
+ remove_env_keys \
309
+ REFLEXIO_API_KEY \
310
+ REFLEXIO_URL \
311
+ REFLEXIO_USER_ID \
312
+ CLAUDE_SMART_READ_ONLY \
313
+ CLAUDE_SMART_USE_LOCAL_CLI \
314
+ CLAUDE_SMART_USE_LOCAL_EMBEDDING
315
+ append_env_value REFLEXIO_URL "$managed_url"
316
+ append_env_value REFLEXIO_API_KEY "$api_key"
317
+ if [ "$read_only" = "yes" ]; then
318
+ append_env_value CLAUDE_SMART_READ_ONLY "1"
319
+ fi
320
+ if [ -n "$managed_user_id" ]; then
321
+ append_env_value REFLEXIO_USER_ID "$managed_user_id"
322
+ fi
323
+ chmod 600 "$REFLEXIO_ENV"
324
+ log "configured managed Reflexio in $REFLEXIO_ENV"
325
+ log "If a real API key was pasted visibly into a terminal or chat, rotate it in Reflexio."
326
+ install_for_host "$host"
327
+ }
328
+
329
+ main "$@"