claude-smart 0.2.48 → 0.2.50
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 +2 -2
- package/README.md +11 -40
- package/bin/claude-smart.js +393 -55
- package/package.json +3 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.coverage +0 -0
- package/plugin/README.md +4 -3
- package/plugin/dashboard/app/api/reflexio/[...path]/route.ts +4 -2
- package/plugin/dashboard/app/dashboard/page.tsx +6 -1
- package/plugin/dashboard/app/preferences/[id]/page.tsx +18 -6
- package/plugin/dashboard/app/preferences/page.tsx +32 -35
- package/plugin/dashboard/app/sessions/[sessionId]/page.tsx +16 -1
- package/plugin/dashboard/app/sessions/page.tsx +2 -0
- package/plugin/dashboard/app/skills/page.tsx +65 -50
- package/plugin/dashboard/app/skills/project/[id]/page.tsx +17 -8
- package/plugin/dashboard/app/skills/shared/[id]/page.tsx +1 -6
- package/plugin/dashboard/components/common/host-badge.tsx +118 -0
- package/plugin/dashboard/components/common/learning-application-badge.tsx +34 -0
- package/plugin/dashboard/components/common/learnings-badge.tsx +1 -1
- package/plugin/dashboard/components/common/page-header.tsx +3 -3
- package/plugin/dashboard/lib/config-file.ts +5 -1
- package/plugin/dashboard/lib/host-attribution.ts +62 -0
- package/plugin/dashboard/lib/session-reader.ts +40 -2
- package/plugin/dashboard/lib/types.ts +7 -1
- package/plugin/opencode/dist/server.mjs +60 -2
- package/plugin/opencode/server.mts +64 -2
- package/plugin/pyproject.toml +2 -2
- package/plugin/scripts/_lib.sh +255 -7
- package/plugin/scripts/backend-python-runner.py +46 -0
- package/plugin/scripts/backend-service.sh +766 -123
- package/plugin/scripts/codex-hook.js +79 -229
- package/plugin/scripts/dashboard-open.sh +6 -4
- package/plugin/scripts/dashboard-service.sh +118 -137
- package/plugin/scripts/ensure-plugin-root.sh +106 -8
- package/plugin/scripts/hook_entry.sh +3 -0
- package/plugin/scripts/opencode-claude-compat.js +8 -1
- package/plugin/scripts/smart-install.sh +116 -21
- package/plugin/src/README.md +1 -1
- package/plugin/src/claude_smart/cli.py +93 -29
- package/plugin/src/claude_smart/context_inject.py +3 -0
- package/plugin/src/claude_smart/env_config.py +56 -11
- package/plugin/src/claude_smart/events/post_tool.py +2 -1
- package/plugin/src/claude_smart/events/session_end.py +2 -1
- package/plugin/src/claude_smart/events/stop.py +3 -0
- package/plugin/src/claude_smart/events/user_prompt.py +2 -1
- package/plugin/src/claude_smart/internal_call.py +5 -2
- package/plugin/src/claude_smart/optimizer_assistant.py +59 -13
- package/plugin/src/claude_smart/publish.py +59 -7
- package/plugin/src/claude_smart/reflexio_adapter.py +137 -14
- package/plugin/src/claude_smart/runtime.py +15 -6
- package/plugin/src/claude_smart/state.py +211 -52
- package/plugin/uv.lock +5 -5
- package/plugin/vendor/reflexio/.env.example +13 -0
- package/plugin/vendor/reflexio/reflexio/README.md +7 -3
- package/plugin/vendor/reflexio/reflexio/__init__.py +12 -0
- package/plugin/vendor/reflexio/reflexio/cli/README.md +3 -0
- package/plugin/vendor/reflexio/reflexio/client/client.py +166 -9
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/src/openclaw_smart/state.py +10 -3
- package/plugin/vendor/reflexio/reflexio/integrations/openclaw/plugin/tests/test_state.py +28 -0
- package/plugin/vendor/reflexio/reflexio/lib/_search.py +41 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/domain/entities.py +195 -25
- package/plugin/vendor/reflexio/reflexio/models/api_schema/eval_overview_schema.py +7 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/internal_schema.py +2 -1
- package/plugin/vendor/reflexio/reflexio/models/api_schema/retriever_schema.py +63 -4
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/converters.py +1 -0
- package/plugin/vendor/reflexio/reflexio/models/api_schema/ui/entities.py +8 -1
- package/plugin/vendor/reflexio/reflexio/models/config_schema.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/README.md +22 -4
- package/plugin/vendor/reflexio/reflexio/server/__init__.py +18 -8
- package/plugin/vendor/reflexio/reflexio/server/__main__.py +6 -0
- package/plugin/vendor/reflexio/reflexio/server/api.py +79 -5
- package/plugin/vendor/reflexio/reflexio/server/billing_meter.py +263 -3
- package/plugin/vendor/reflexio/reflexio/server/callback_executor.py +164 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_embedding.py +81 -81
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_subprocess.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/_litellm_text_generation.py +63 -6
- package/plugin/vendor/reflexio/reflexio/server/llm/embedding_service.py +19 -52
- package/plugin/vendor/reflexio/reflexio/server/llm/litellm_client.py +1 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/model_defaults.py +28 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/claude_code_provider.py +9 -1
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedder_warmup.py +329 -0
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/embedding_service_provider.py +85 -10
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/local_embedding_provider.py +199 -2
- package/plugin/vendor/reflexio/reflexio/server/llm/providers/nomic_embedding_provider.py +77 -9
- package/plugin/vendor/reflexio/reflexio/server/org_fanout.py +184 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/document_expansion/v1.1.0.prompt.md +32 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.3.3.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/playbook_consolidation/v2.4.0.prompt.md +63 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/query_reformulation/v2.0.0.prompt.md +30 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/retrieved_learning_impact/v1.0.0.prompt.md +51 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/retrieved_learning_relevance/v1.0.0.prompt.md +39 -0
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.0.0.prompt.md +1 -1
- package/plugin/vendor/reflexio/reflexio/server/prompt/prompt_bank/shadow_comparison/v1.1.0.prompt.md +43 -0
- package/plugin/vendor/reflexio/reflexio/server/routes/config.py +3 -3
- package/plugin/vendor/reflexio/reflexio/server/routes/evaluation.py +122 -28
- package/plugin/vendor/reflexio/reflexio/server/routes/interactions.py +63 -2
- package/plugin/vendor/reflexio/reflexio/server/routes/system.py +22 -3
- package/plugin/vendor/reflexio/reflexio/server/scheduling.py +64 -3
- package/plugin/vendor/reflexio/reflexio/server/services/README.md +6 -4
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/README.md +3 -2
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/_eval_health.py +41 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/components/retrieved_learning_evaluator.py +554 -0
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/regen_jobs.py +35 -1
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/runner.py +253 -101
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/scheduler.py +5 -7
- package/plugin/vendor/reflexio/reflexio/server/services/agent_success_evaluation/service.py +27 -0
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_extraction_lifecycle.py +11 -5
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_should_run.py +4 -4
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation/_usage_billing.py +6 -2
- package/plugin/vendor/reflexio/reflexio/server/services/base_generation_service.py +255 -74
- package/plugin/vendor/reflexio/reflexio/server/services/deduplication_utils.py +72 -0
- package/plugin/vendor/reflexio/reflexio/server/services/deferred_learning_plan.py +270 -0
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/__init__.py +13 -0
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/scheduler.py +142 -0
- package/plugin/vendor/reflexio/reflexio/server/services/durable_learning/worker.py +262 -0
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/hero_state.py +2 -11
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/components/rule_attribution.py +6 -2
- package/plugin/vendor/reflexio/reflexio/server/services/evaluation_overview/service.py +17 -13
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/agent_run_records.py +18 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/outcome.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/prior_answer_search.py +1 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resumable_agent.py +2 -1
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_scheduler.py +1 -3
- package/plugin/vendor/reflexio/reflexio/server/services/extraction/resume_worker.py +66 -0
- package/plugin/vendor/reflexio/reflexio/server/services/generation_service.py +640 -80
- package/plugin/vendor/reflexio/reflexio/server/services/governance/service.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/gc_scheduler.py +179 -99
- package/plugin/vendor/reflexio/reflexio/server/services/lineage/vector_backfill_sweep.py +139 -0
- package/plugin/vendor/reflexio/reflexio/server/services/operation_state_utils.py +66 -27
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/aggregation_trigger.py +177 -0
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/aggregator.py +68 -2
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/consolidator.py +360 -49
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/components/extractor.py +27 -30
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/playbook_edit_apply.py +8 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook/service.py +137 -69
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/optimizer.py +20 -1
- package/plugin/vendor/reflexio/reflexio/server/services/playbook_optimizer/scheduler.py +13 -6
- package/plugin/vendor/reflexio/reflexio/server/services/pre_retrieval/_query_reformulator.py +40 -25
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/consolidator.py +12 -39
- package/plugin/vendor/reflexio/reflexio/server/services/profile/components/extractor.py +30 -35
- package/plugin/vendor/reflexio/reflexio/server/services/profile/service.py +166 -66
- package/plugin/vendor/reflexio/reflexio/server/services/reflection/service.py +457 -107
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/session_dedup.py +127 -0
- package/plugin/vendor/reflexio/reflexio/server/services/retrieval/temporal.py +104 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/dispatcher.py +139 -0
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/judge.py +16 -6
- package/plugin/vendor/reflexio/reflexio/server/services/shadow_comparison/worker.py +137 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/governance_validation.py +12 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/lifecycle_filters.py +54 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention.py +41 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/retention_mixin.py +40 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/__init__.py +2 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_base.py +190 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_extras.py +11 -4
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_governance.py +28 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_learning_jobs.py +414 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_lineage.py +11 -5
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_requests.py +8 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/_shadow_verdicts.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_deletion.py +16 -5
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/base/_fts_vec.py +86 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_erase_execution.py +104 -42
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/governance/_subject_barrier.py +7 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_agent.py +59 -7
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_eval_results.py +430 -5
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_source_linkage.py +8 -3
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/playbook/_user.py +57 -12
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_interaction_store.py +197 -12
- package/plugin/vendor/reflexio/reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py +70 -11
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/__init__.py +17 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_commit_scope.py +9 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_extras.py +9 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_learning_jobs.py +269 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_operations.py +7 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_retrieval_log.py +3 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/_shadow_verdicts.py +4 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/agent_run/_models.py +12 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/evaluation_state_keys.py +78 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_agent.py +38 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_eval_results.py +171 -0
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/playbook/_user.py +52 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_interaction_store.py +82 -1
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/profiles/_profile_store.py +74 -2
- package/plugin/vendor/reflexio/reflexio/server/services/storage/storage_base/retrieved_learning_state.py +226 -0
- package/plugin/vendor/reflexio/reflexio/server/services/tagging/tagging_scheduler.py +5 -6
- package/plugin/vendor/reflexio/reflexio/server/services/unified_search_service.py +209 -29
- package/plugin/vendor/reflexio/reflexio/server/usage_metrics.py +3 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_mock.py +61 -0
- package/plugin/vendor/reflexio/reflexio/test_support/llm_model_registry.py +33 -0
- package/plugin/vendor/reflexio/reflexio/server/services/search/__init__.py +0 -0
package/plugin/scripts/_lib.sh
CHANGED
|
@@ -71,7 +71,11 @@ claude_smart_prepend_astral_bins() {
|
|
|
71
71
|
claude_smart_prepend_node_bins() {
|
|
72
72
|
local _CS_NODE_ROOT
|
|
73
73
|
_CS_NODE_ROOT="$HOME/.claude-smart/node/current"
|
|
74
|
-
|
|
74
|
+
if claude_smart_is_windows; then
|
|
75
|
+
export PATH="$_CS_NODE_ROOT:$PATH"
|
|
76
|
+
else
|
|
77
|
+
export PATH="$_CS_NODE_ROOT/bin:$_CS_NODE_ROOT:$PATH"
|
|
78
|
+
fi
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
claude_smart_env_unquote() {
|
|
@@ -89,7 +93,7 @@ claude_smart_env_unquote() {
|
|
|
89
93
|
claude_smart_source_reflexio_env() {
|
|
90
94
|
# claude-smart's env lives at ~/.claude-smart/.env (kept separate from the OSS
|
|
91
95
|
# reflexio default ~/.reflexio/.env). Stays in sync with
|
|
92
|
-
# env_config.
|
|
96
|
+
# env_config.CLAUDE_SMART_ENV_PATH and the REFLEXIO_ENV_FILE export in
|
|
93
97
|
# backend-service.sh.
|
|
94
98
|
local env_file line key value
|
|
95
99
|
env_file="$HOME/.claude-smart/.env"
|
|
@@ -117,7 +121,7 @@ claude_smart_source_reflexio_env() {
|
|
|
117
121
|
;;
|
|
118
122
|
# CLAUDE_SMART_* flags: respect anything the caller already exported so
|
|
119
123
|
# per-session overrides (e.g., a manual test) take precedence over the file.
|
|
120
|
-
CLAUDE_SMART_USE_LOCAL_CLI|CLAUDE_SMART_USE_LOCAL_EMBEDDING|CLAUDE_SMART_BACKEND_AUTOSTART|CLAUDE_SMART_DASHBOARD_AUTOSTART|CLAUDE_SMART_CLI_PATH|CLAUDE_SMART_CLI_TIMEOUT|CLAUDE_SMART_STATE_DIR|CLAUDE_SMART_ENABLE_OPTIMIZER)
|
|
124
|
+
CLAUDE_SMART_USE_LOCAL_CLI|CLAUDE_SMART_USE_LOCAL_EMBEDDING|CLAUDE_SMART_HOST|CLAUDE_SMART_BACKEND_AUTOSTART|CLAUDE_SMART_DASHBOARD_AUTOSTART|CLAUDE_SMART_CLI_PATH|CLAUDE_SMART_OPENCODE_PATH|CLAUDE_SMART_CLI_TIMEOUT|CLAUDE_SMART_STATE_DIR|CLAUDE_SMART_ENABLE_OPTIMIZER)
|
|
121
125
|
if [ -z "$(eval "printf '%s' \"\${$key:-}\"")" ]; then
|
|
122
126
|
value="$(claude_smart_env_unquote "$value")"
|
|
123
127
|
export "$key=$value"
|
|
@@ -139,12 +143,23 @@ claude_smart_reflexio_url_is_remote() {
|
|
|
139
143
|
return 0
|
|
140
144
|
}
|
|
141
145
|
|
|
146
|
+
claude_smart_derive_reflexio_url_from_backend_port() {
|
|
147
|
+
local port default_url
|
|
148
|
+
port="${BACKEND_PORT:-8071}"
|
|
149
|
+
default_url="http://localhost:$port/"
|
|
150
|
+
case "${REFLEXIO_URL:-}" in
|
|
151
|
+
""|"http://localhost:8071"|"http://localhost:8071/"|"http://127.0.0.1:8071"|"http://127.0.0.1:8071/")
|
|
152
|
+
export REFLEXIO_URL="$default_url"
|
|
153
|
+
;;
|
|
154
|
+
esac
|
|
155
|
+
}
|
|
156
|
+
|
|
142
157
|
claude_smart_is_internal_invocation_env() {
|
|
143
158
|
if [ "${CLAUDE_SMART_INTERNAL:-}" = "1" ]; then
|
|
144
159
|
return 0
|
|
145
160
|
fi
|
|
146
161
|
case "${CLAUDE_CODE_ENTRYPOINT:-}" in
|
|
147
|
-
""|"cli"|"claude-desktop") return 1 ;;
|
|
162
|
+
""|"cli"|"claude-desktop"|"claude-vscode"|"claude-jetbrains") return 1 ;;
|
|
148
163
|
*) return 0 ;;
|
|
149
164
|
esac
|
|
150
165
|
}
|
|
@@ -210,16 +225,54 @@ claude_smart_is_windows() {
|
|
|
210
225
|
esac
|
|
211
226
|
}
|
|
212
227
|
|
|
228
|
+
claude_smart_to_windows_path() {
|
|
229
|
+
local path
|
|
230
|
+
path="$1"
|
|
231
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
232
|
+
cygpath -w "$path"
|
|
233
|
+
return $?
|
|
234
|
+
fi
|
|
235
|
+
# Convert MSYS/Cygwin/WSL-style paths to native Windows paths for cmd.exe.
|
|
236
|
+
printf '%s\n' "$path" | awk '
|
|
237
|
+
function slash_to_backslash(value) {
|
|
238
|
+
gsub(/\//, "\\", value)
|
|
239
|
+
return value
|
|
240
|
+
}
|
|
241
|
+
function drive_path(drive, rest) {
|
|
242
|
+
drive = toupper(drive)
|
|
243
|
+
sub(/^\//, "", rest)
|
|
244
|
+
if (rest == "") {
|
|
245
|
+
return drive ":\\"
|
|
246
|
+
}
|
|
247
|
+
return drive ":\\" slash_to_backslash(rest)
|
|
248
|
+
}
|
|
249
|
+
{
|
|
250
|
+
normalized = $0
|
|
251
|
+
gsub(/\\/, "/", normalized)
|
|
252
|
+
if (normalized ~ /^[A-Za-z]:($|\/)/) {
|
|
253
|
+
print drive_path(substr(normalized, 1, 1), substr(normalized, 3))
|
|
254
|
+
} else if (normalized ~ /^\/cygdrive\/[A-Za-z]($|\/)/) {
|
|
255
|
+
print drive_path(substr(normalized, 11, 1), substr(normalized, 12))
|
|
256
|
+
} else if (normalized ~ /^\/mnt\/[A-Za-z]($|\/)/) {
|
|
257
|
+
print drive_path(substr(normalized, 6, 1), substr(normalized, 7))
|
|
258
|
+
} else if (normalized ~ /^\/[A-Za-z]($|\/)/) {
|
|
259
|
+
print drive_path(substr(normalized, 2, 1), substr(normalized, 3))
|
|
260
|
+
} else {
|
|
261
|
+
print slash_to_backslash(normalized)
|
|
262
|
+
}
|
|
263
|
+
}'
|
|
264
|
+
}
|
|
265
|
+
|
|
213
266
|
# Print the absolute path of a working python interpreter, or nothing
|
|
214
267
|
# (and return non-zero) if none is usable. On Windows, `python3` is
|
|
215
268
|
# usually the Microsoft Store "App Execution Alias" stub at
|
|
216
269
|
# %LocalAppData%\Microsoft\WindowsApps\python3.exe — `command -v python3`
|
|
217
270
|
# returns truthy but invoking it just prints a "Python was not found"
|
|
218
271
|
# message and exits non-zero. We probe with `-V` to filter the stub out
|
|
219
|
-
# and prefer
|
|
272
|
+
# and prefer the Windows `py` launcher before `python`/`python3`.
|
|
220
273
|
claude_smart_resolve_python() {
|
|
221
274
|
if claude_smart_is_windows; then
|
|
222
|
-
for cand in python python3; do
|
|
275
|
+
for cand in py python python3; do
|
|
223
276
|
if command -v "$cand" >/dev/null 2>&1 && "$cand" -V >/dev/null 2>&1; then
|
|
224
277
|
command -v "$cand"
|
|
225
278
|
return 0
|
|
@@ -508,7 +561,7 @@ claude_smart_node_satisfies() {
|
|
|
508
561
|
|
|
509
562
|
claude_smart_resolve_npm() {
|
|
510
563
|
local cand
|
|
511
|
-
for cand in npm npm.cmd; do
|
|
564
|
+
for cand in npm npm.cmd npm.exe; do
|
|
512
565
|
if command -v "$cand" >/dev/null 2>&1; then
|
|
513
566
|
command -v "$cand"
|
|
514
567
|
return 0
|
|
@@ -517,6 +570,16 @@ claude_smart_resolve_npm() {
|
|
|
517
570
|
return 1
|
|
518
571
|
}
|
|
519
572
|
|
|
573
|
+
claude_smart_opencode_compat_path() {
|
|
574
|
+
local plugin_root filename
|
|
575
|
+
plugin_root="$1"
|
|
576
|
+
filename="opencode-claude-compat"
|
|
577
|
+
if claude_smart_is_windows; then
|
|
578
|
+
filename="opencode-claude-compat.cmd"
|
|
579
|
+
fi
|
|
580
|
+
printf '%s\n' "$plugin_root/scripts/$filename"
|
|
581
|
+
}
|
|
582
|
+
|
|
520
583
|
claude_smart_npm_available() {
|
|
521
584
|
local npm_bin
|
|
522
585
|
npm_bin=$(claude_smart_resolve_npm || true)
|
|
@@ -651,6 +714,191 @@ claude_smart_kill_tree() {
|
|
|
651
714
|
kill -KILL -- "-$pid" 2>/dev/null || true
|
|
652
715
|
}
|
|
653
716
|
|
|
717
|
+
claude_smart_now_epoch() {
|
|
718
|
+
date +%s 2>/dev/null || {
|
|
719
|
+
_CS_PY=$(claude_smart_resolve_python 2>/dev/null || true)
|
|
720
|
+
[ -n "$_CS_PY" ] || return 1
|
|
721
|
+
"$_CS_PY" - <<'PY'
|
|
722
|
+
import time
|
|
723
|
+
|
|
724
|
+
print(int(time.time()))
|
|
725
|
+
PY
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
claude_smart_path_mtime_epoch() {
|
|
730
|
+
path="$1"
|
|
731
|
+
mtime=""
|
|
732
|
+
[ -e "$path" ] || return 1
|
|
733
|
+
mtime="$(stat -f %m "$path" 2>/dev/null || true)"
|
|
734
|
+
case "$mtime" in
|
|
735
|
+
''|*[!0-9]*) ;;
|
|
736
|
+
*) printf '%s\n' "$mtime"; return 0 ;;
|
|
737
|
+
esac
|
|
738
|
+
mtime="$(stat -c %Y "$path" 2>/dev/null || true)"
|
|
739
|
+
case "$mtime" in
|
|
740
|
+
''|*[!0-9]*) ;;
|
|
741
|
+
*) printf '%s\n' "$mtime"; return 0 ;;
|
|
742
|
+
esac
|
|
743
|
+
_CS_PY=$(claude_smart_resolve_python 2>/dev/null || true)
|
|
744
|
+
[ -n "$_CS_PY" ] || return 1
|
|
745
|
+
"$_CS_PY" - "$path" <<'PY'
|
|
746
|
+
import os
|
|
747
|
+
import sys
|
|
748
|
+
|
|
749
|
+
print(int(os.path.getmtime(sys.argv[1])))
|
|
750
|
+
PY
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
claude_smart_service_lock_stale_seconds() {
|
|
754
|
+
value="${CLAUDE_SMART_SERVICE_LOCK_STALE_SECONDS:-60}"
|
|
755
|
+
case "$value" in
|
|
756
|
+
''|*[!0-9]*) printf '%s\n' "60" ;;
|
|
757
|
+
*) printf '%s\n' "$value" ;;
|
|
758
|
+
esac
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
claude_smart_service_lock() {
|
|
762
|
+
name="$1"
|
|
763
|
+
lock_dir="$HOME/.claude-smart/$name.start.lock"
|
|
764
|
+
pid_file="$lock_dir/pid"
|
|
765
|
+
mkdir -p "$HOME/.claude-smart"
|
|
766
|
+
for _ in 1 2 3; do
|
|
767
|
+
if mkdir "$lock_dir" 2>/dev/null; then
|
|
768
|
+
printf '%s\n' "$$" > "$pid_file"
|
|
769
|
+
return 0
|
|
770
|
+
fi
|
|
771
|
+
|
|
772
|
+
lock_pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
773
|
+
now="$(claude_smart_now_epoch 2>/dev/null || printf '%s\n' "0")"
|
|
774
|
+
mtime="$(claude_smart_path_mtime_epoch "$lock_dir" 2>/dev/null || printf '%s\n' "$now")"
|
|
775
|
+
age=$((now - mtime))
|
|
776
|
+
stale_after="$(claude_smart_service_lock_stale_seconds)"
|
|
777
|
+
|
|
778
|
+
if [ -n "$lock_pid" ] && kill -0 "$lock_pid" 2>/dev/null; then
|
|
779
|
+
return 1
|
|
780
|
+
fi
|
|
781
|
+
if [ -z "$lock_pid" ] && [ "$age" -lt "$stale_after" ]; then
|
|
782
|
+
return 1
|
|
783
|
+
fi
|
|
784
|
+
if [ -n "$lock_pid" ] || [ "$age" -ge "$stale_after" ]; then
|
|
785
|
+
stale_dir="$lock_dir.stale.$$"
|
|
786
|
+
if mv "$lock_dir" "$stale_dir" 2>/dev/null; then
|
|
787
|
+
rm -rf "$stale_dir"
|
|
788
|
+
continue
|
|
789
|
+
fi
|
|
790
|
+
fi
|
|
791
|
+
return 1
|
|
792
|
+
done
|
|
793
|
+
return 1
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
claude_smart_service_unlock() {
|
|
797
|
+
name="$1"
|
|
798
|
+
lock_dir="$HOME/.claude-smart/$name.start.lock"
|
|
799
|
+
pid_file="$lock_dir/pid"
|
|
800
|
+
[ -d "$lock_dir" ] || return 0
|
|
801
|
+
lock_pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
802
|
+
[ "$lock_pid" = "$$" ] || return 0
|
|
803
|
+
rm -rf "$lock_dir"
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
claude_smart_powershell_bin() {
|
|
807
|
+
for cand in powershell.exe powershell pwsh.exe pwsh; do
|
|
808
|
+
if command -v "$cand" >/dev/null 2>&1; then
|
|
809
|
+
command -v "$cand"
|
|
810
|
+
return 0
|
|
811
|
+
fi
|
|
812
|
+
done
|
|
813
|
+
return 1
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
claude_smart_port_listener_pids() {
|
|
817
|
+
port="$1"
|
|
818
|
+
if claude_smart_is_windows; then
|
|
819
|
+
ps_bin="$(claude_smart_powershell_bin 2>/dev/null || true)"
|
|
820
|
+
if [ -n "$ps_bin" ]; then
|
|
821
|
+
PORT="$port" "$ps_bin" -NoProfile -ExecutionPolicy Bypass -Command \
|
|
822
|
+
'$ErrorActionPreference="SilentlyContinue"; Get-NetTCPConnection -LocalPort $env:PORT -State Listen | Select-Object -ExpandProperty OwningProcess' \
|
|
823
|
+
2>/dev/null | tr -d '\r' | awk 'NF && !seen[$1]++ {print $1}'
|
|
824
|
+
return 0
|
|
825
|
+
fi
|
|
826
|
+
if command -v netstat >/dev/null 2>&1; then
|
|
827
|
+
netstat -ano 2>/dev/null | awk -v port=":$port" '
|
|
828
|
+
$1 ~ /^TCP/ && $2 ~ port "$" && $4 == "LISTENING" && !seen[$5]++ {print $5}
|
|
829
|
+
'
|
|
830
|
+
return 0
|
|
831
|
+
fi
|
|
832
|
+
fi
|
|
833
|
+
command -v lsof >/dev/null 2>&1 || return 0
|
|
834
|
+
lsof -tiTCP:"$port" -sTCP:LISTEN -P -n 2>/dev/null | awk 'NF && !seen[$1]++ {print $1}'
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
claude_smart_pid_command() {
|
|
838
|
+
pid="$1"
|
|
839
|
+
if claude_smart_is_windows; then
|
|
840
|
+
ps_bin="$(claude_smart_powershell_bin 2>/dev/null || true)"
|
|
841
|
+
if [ -n "$ps_bin" ]; then
|
|
842
|
+
PID="$pid" "$ps_bin" -NoProfile -ExecutionPolicy Bypass -Command \
|
|
843
|
+
'$ErrorActionPreference="SilentlyContinue"; $p=Get-CimInstance Win32_Process -Filter "ProcessId=$env:PID"; if ($p) { $p.CommandLine }' \
|
|
844
|
+
2>/dev/null | tr -d '\r'
|
|
845
|
+
return 0
|
|
846
|
+
fi
|
|
847
|
+
if command -v tasklist >/dev/null 2>&1; then
|
|
848
|
+
tasklist //FI "PID eq $pid" //FO CSV //NH 2>/dev/null \
|
|
849
|
+
| awk -F, 'NR==1 {gsub(/^"|"$/, "", $1); print $1}'
|
|
850
|
+
return 0
|
|
851
|
+
fi
|
|
852
|
+
fi
|
|
853
|
+
command -v ps >/dev/null 2>&1 || return 0
|
|
854
|
+
ps -ww -p "$pid" -o command= 2>/dev/null || true
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
claude_smart_pid_parent() {
|
|
858
|
+
pid="$1"
|
|
859
|
+
if claude_smart_is_windows; then
|
|
860
|
+
ps_bin="$(claude_smart_powershell_bin 2>/dev/null || true)"
|
|
861
|
+
if [ -n "$ps_bin" ]; then
|
|
862
|
+
PID="$pid" "$ps_bin" -NoProfile -ExecutionPolicy Bypass -Command \
|
|
863
|
+
'$ErrorActionPreference="SilentlyContinue"; $p=Get-CimInstance Win32_Process -Filter "ProcessId=$env:PID"; if ($p) { $p.ParentProcessId }' \
|
|
864
|
+
2>/dev/null | tr -d '\r'
|
|
865
|
+
return 0
|
|
866
|
+
fi
|
|
867
|
+
fi
|
|
868
|
+
command -v ps >/dev/null 2>&1 || return 0
|
|
869
|
+
ps -p "$pid" -o ppid= 2>/dev/null | awk 'NF {print $1; exit}' || true
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
claude_smart_port_holder() {
|
|
873
|
+
port="$1"
|
|
874
|
+
pid="$(claude_smart_port_listener_pids "$port" | head -n1)"
|
|
875
|
+
[ -n "$pid" ] || return 0
|
|
876
|
+
cmdline="$(claude_smart_pid_command "$pid" | head -n1)"
|
|
877
|
+
[ -n "$cmdline" ] || cmdline="unknown"
|
|
878
|
+
printf '%s (pid %s)\n' "$cmdline" "$pid"
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
claude_smart_reap_port_listeners_matching() {
|
|
882
|
+
port="$1"
|
|
883
|
+
shift || true
|
|
884
|
+
[ "$#" -gt 0 ] || return 1
|
|
885
|
+
killed=1
|
|
886
|
+
pids="$(claude_smart_port_listener_pids "$port" || true)"
|
|
887
|
+
[ -n "$pids" ] || return 1
|
|
888
|
+
for pid in $pids; do
|
|
889
|
+
cmdline="$(claude_smart_pid_command "$pid" | tr '\n' ' ' || true)"
|
|
890
|
+
[ -n "$cmdline" ] || continue
|
|
891
|
+
for pattern in "$@"; do
|
|
892
|
+
if [[ "$cmdline" == $pattern ]]; then
|
|
893
|
+
claude_smart_kill_tree "$pid"
|
|
894
|
+
killed=0
|
|
895
|
+
break
|
|
896
|
+
fi
|
|
897
|
+
done
|
|
898
|
+
done
|
|
899
|
+
return "$killed"
|
|
900
|
+
}
|
|
901
|
+
|
|
654
902
|
# Return 0 (true) if $1 names a pid file whose pid is currently alive.
|
|
655
903
|
# Silent on missing/empty/stale files.
|
|
656
904
|
claude_smart_pid_alive_file() {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Run Reflexio CLI with claude-smart metadata visible in process argv."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import runpy
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> int:
|
|
12
|
+
"""Mirror claude-smart metadata into env and delegate to Reflexio CLI.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
None: Reads process argv. Arguments before ``--`` are
|
|
16
|
+
``--claude-smart-*`` metadata kept visible in the process command
|
|
17
|
+
line; arguments after ``--`` become ``reflexio.cli`` arguments.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
int: Exit status. Returns ``2`` when required argument separators or
|
|
21
|
+
Reflexio CLI arguments are missing.
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
separator = sys.argv.index("--")
|
|
25
|
+
except ValueError:
|
|
26
|
+
return 2
|
|
27
|
+
|
|
28
|
+
metadata_args = sys.argv[1:separator]
|
|
29
|
+
reflexio_args = sys.argv[separator + 1 :]
|
|
30
|
+
if not reflexio_args:
|
|
31
|
+
return 2
|
|
32
|
+
|
|
33
|
+
for arg in metadata_args:
|
|
34
|
+
if not arg.startswith("--claude-smart-") or "=" not in arg:
|
|
35
|
+
continue
|
|
36
|
+
key, value = arg[2:].split("=", 1)
|
|
37
|
+
env_key = key.replace("-", "_").upper()
|
|
38
|
+
os.environ.setdefault(env_key, value)
|
|
39
|
+
|
|
40
|
+
sys.argv = ["reflexio.cli", *reflexio_args]
|
|
41
|
+
runpy.run_module("reflexio.cli", run_name="__main__")
|
|
42
|
+
return 0
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
raise SystemExit(main())
|