From c23b06c72cb8f30312fde10ff5f0b64771146a47 Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 21 Feb 2026 22:49:52 +0800 Subject: [PATCH 1/3] docs: update directory structure in CLAUDE.md Remove x402curl/ and update skill paths to claude/ and openclaw/ --- CLAUDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 92c3fdc..3724a3a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,5 +37,5 @@ Payment skill for AI agents (Claude Code, OpenClaw, OpenCode) to make and receiv - `get-address/` - Get wallet address and balance - `pay/` - Make payments - `payment-config/` - Configuration management -- `x402curl/` - HTTP client with 402 payment handling -- `skill/` - Skill files for Claude Code +- `claude/skills/payment/` - Skill files for Claude Code +- `openclaw/skills/payment/` - Skill files for OpenClaw From 41c16efd12a4a2afc9f12f79927f0cbb3386975f Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 21 Feb 2026 22:49:58 +0800 Subject: [PATCH 2/3] docs: clarify data directory resolution and license info - Update data directory resolution order (env var, scripts/, cwd) - Update license section to reference Cargo.toml MIT declaration --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d359b85..83f24aa 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,10 @@ All personal data is stored in the skill root directory (the parent of the `scri └── password.txt # Wallet password (auto-generated, 600 permissions) ``` -The data directory is determined at runtime via `std::env::current_exe()` — each binary resolves paths relative to its own location (`../` from the `scripts/` directory). +The data directory is resolved at runtime: +- `PAYMENT_SKILL_DATA_DIR` if set +- otherwise, `../` from the `scripts/` directory in installed skill layouts +- otherwise, current working directory during local `cargo run` development ## Skill Directory Structure @@ -171,4 +174,4 @@ The project uses GitHub Actions to build binaries for all supported platforms. S ## License -See [LICENSE](LICENSE) for details. +License is declared as MIT in `Cargo.toml`. The project owner should provide the canonical license file. From 715baec8bf2e223ae349fa3c589ff5b38bb00f19 Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 21 Feb 2026 22:50:05 +0800 Subject: [PATCH 3/3] refactor: improve data directory resolution with env var support - Add PAYMENT_SKILL_DATA_DIR environment variable support - Add resolve_data_dir_from_exe() helper for better layout detection - Distinguish between installed skill layout and local cargo run - Fall back to cwd for local development --- payment-common/src/lib.rs | 51 +++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/payment-common/src/lib.rs b/payment-common/src/lib.rs index 2bf6d0c..2639e99 100644 --- a/payment-common/src/lib.rs +++ b/payment-common/src/lib.rs @@ -6,18 +6,55 @@ pub use config::Config; pub use error::{Error, Result}; pub use wallet::{Wallet, WalletInfo}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -/// Get the default data directory (parent of the directory containing the executable). +/// Resolve the default data directory. /// -/// Given the installed layout where binaries live in `scripts/`, this returns the -/// skill root directory (e.g., `~/.openclaw/skills/payment/`). +/// Resolution order: +/// 1. `PAYMENT_SKILL_DATA_DIR` environment variable (if set) +/// 2. Installed layout: if executable is in `.../scripts/`, use its parent +/// 3. Local development (`cargo run` from `target/{debug,release}`): use current working directory +/// 4. Fallback: executable directory pub fn default_data_dir() -> PathBuf { + if let Ok(dir) = std::env::var("PAYMENT_SKILL_DATA_DIR") { + let trimmed = dir.trim(); + if !trimmed.is_empty() { + return PathBuf::from(trimmed); + } + } + + let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); + std::env::current_exe() .ok() - .and_then(|exe| exe.parent().map(|p| p.to_path_buf())) - .and_then(|dir| dir.parent().map(|p| p.to_path_buf())) - .unwrap_or_else(|| PathBuf::from(".")) + .and_then(|exe| resolve_data_dir_from_exe(&exe, &cwd)) + .unwrap_or(cwd) +} + +fn resolve_data_dir_from_exe(exe: &Path, cwd: &Path) -> Option { + let exe_dir = exe.parent()?; + + // Installed skill layout: /scripts/ + if exe_dir.file_name().and_then(|n| n.to_str()) == Some("scripts") { + return exe_dir.parent().map(|p| p.to_path_buf()); + } + + // Local cargo layout: /target/{debug,release}/ + let is_target_profile = matches!( + exe_dir.file_name().and_then(|n| n.to_str()), + Some("debug" | "release") + ); + let is_under_target = exe_dir + .parent() + .and_then(|p| p.file_name()) + .and_then(|n| n.to_str()) + == Some("target"); + + if is_target_profile && is_under_target { + return Some(cwd.to_path_buf()); + } + + Some(exe_dir.to_path_buf()) } /// Get the default wallet path (data_dir/wallet.json)