Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions README-VI.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,55 @@ Sau khi chạy xong, bộ cài sẽ tự động tạo:
- `aim.bat`: Cho phép bạn gõ trực tiếp `aim <lệnh>` trong CMD hoặc PowerShell.
- `aim.sh`: Cho phép bạn gõ `aim` trên môi trường Unix/Linux/macOS.

### Cài một dòng (one-line install)

**Windows (PowerShell):**
```powershell
iwr -useb https://raw.githubusercontent.com/phuonghx/aim-cli/main/install.ps1 | iex
```

**macOS / Linux:**
```bash
curl -fsSL https://raw.githubusercontent.com/phuonghx/aim-cli/main/install.sh | bash
```

Sau khi cài, chạy `aim init` trong thư mục dự án để bắt đầu.

### Khắc phục lỗi `'aim' is not recognized` / `command not found`

Lỗi này gần như luôn do pip cài file thực thi `aim` vào thư mục **Scripts**
(Windows) hoặc **bin** (macOS/Linux) chưa nằm trong `PATH`. Ngay khi cài, pip
thường in cảnh báo: `WARNING: The script aim is installed in '...' which is not on PATH`.

Bộ cài một dòng nay đã **tự phát hiện** và **hỏi bạn có muốn thêm vào PATH không**
(gõ `Y` để đồng ý), sau đó nhắc bạn mở terminal mới. Nếu vẫn lỗi, sửa thủ công:

**Windows (PowerShell)** — tìm thư mục Scripts rồi thêm vào PATH của user:
```powershell
# Xem thư mục chứa console scripts (kiểm tra cả 2 dòng xem dòng nào có aim.exe):
python -c "import sysconfig; print(sysconfig.get_paths('nt_user')['scripts']); print(sysconfig.get_paths('nt')['scripts'])"

# Thêm đúng thư mục (thay đường dẫn) vào PATH user, rồi mở lại terminal:
$d = "C:\Users\<ban>\AppData\Roaming\Python\Python3XX\Scripts"
[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','User').TrimEnd(';') + ';' + $d, 'User')
```
> Lưu ý: câu lỗi `'aim' is not recognized as an internal or external command` là
> của **cmd.exe**. Nếu bạn cài bằng PowerShell thì cũng nên chạy `aim` trong PowerShell.

**macOS / Linux** — thêm thư mục bin vào file khởi động của shell:
```bash
# Xem thư mục chứa console scripts (thường là ~/.local/bin):
python3 -c "import sysconfig; print(sysconfig.get_paths('posix_user')['scripts'])"

echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.zshrc # hoặc ~/.bashrc
source ~/.zshrc
```

**Cách chạy tạm không cần sửa PATH (mọi hệ điều hành):**
```bash
python -m aim.aim_cli init
```

---

## 🔄 Đồng Bộ Hóa Hướng Dẫn (Sync)
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,43 @@ aim ingest --dry-run # preview
aim ingest && aim sync # consolidate, then re-emit everywhere
```

### Troubleshooting: `aim` is not recognized / command not found

This almost always means pip installed the `aim` executable into a **Scripts**
folder (Windows) or **bin** folder (macOS/Linux) that is not on your `PATH`.
During install pip even prints a hint such as
`WARNING: The script aim is installed in '...' which is not on PATH`.

The one-line installers now detect this and offer to add the folder to your
`PATH` for you (answer `Y` at the prompt), then ask you to open a new terminal.
If you still hit the error, fix it manually:

**Windows (PowerShell)** — find the folder and add it to your user PATH:
```powershell
# Show where the console scripts live (check both lines for aim.exe):
python -c "import sysconfig; print(sysconfig.get_paths('nt_user')['scripts']); print(sysconfig.get_paths('nt')['scripts'])"

# Add the right folder (replace the path) to your user PATH, then reopen the terminal:
$d = "C:\Users\<you>\AppData\Roaming\Python\Python3XX\Scripts"
[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','User').TrimEnd(';') + ';' + $d, 'User')
```
> Tip: the error text `'aim' is not recognized as an internal or external command`
> is from **cmd.exe**. If you installed in PowerShell, run `aim` in PowerShell too.

**macOS / Linux** — add the bin folder to your shell startup file:
```bash
# Show where the console scripts live (usually ~/.local/bin):
python3 -c "import sysconfig; print(sysconfig.get_paths('posix_user')['scripts'])"

echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.zshrc # or ~/.bashrc
source ~/.zshrc
```

**No-PATH workaround (any OS)** — run AIM as a module without changing PATH:
```bash
python -m aim.aim_cli init
```

### From a repository checkout (development)
Run via the included wrappers without installing:
- `aim.bat` (Windows) / `aim.sh` (Unix-like shells) at the repo root.
Expand Down
114 changes: 112 additions & 2 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,116 @@ Write-Host ""
Write-Host "=========================================" -ForegroundColor Green
Write-Host " [+] AIM installed successfully! " -ForegroundColor Green
Write-Host "=========================================" -ForegroundColor Green
Write-Host "You can now run 'aim' command directly from your terminal."
Write-Host "Run 'aim init' in your project directory to get started."

# 4. Make sure the 'aim' command is reachable (fix the classic
# "'aim' is not recognized..." problem) by locating the Scripts folder
# where pip placed aim.exe and optionally adding it to the user PATH.

function Get-AimScriptDir {
param([string]$PythonCmd)

# If 'aim' already resolves, use its real folder.
$cmd = Get-Command aim -ErrorAction SilentlyContinue
if ($cmd -and $cmd.Source) { return (Split-Path -Parent $cmd.Source) }

# Ask Python where console scripts are installed (user scheme first, then global).
$pyCode = @'
import sysconfig
dirs = []
for scheme in ("nt_user", "nt"):
try:
d = sysconfig.get_paths(scheme).get("scripts")
if d:
dirs.append(d)
except Exception:
pass
for d in dirs:
print(d)
'@
$candidates = & $PythonCmd -c $pyCode

# Prefer a folder that actually contains aim.exe.
foreach ($d in $candidates) {
if ($d -and (Test-Path (Join-Path $d 'aim.exe'))) { return $d }
}
if ($candidates) { return ($candidates | Select-Object -First 1) }
return $null
}

function Test-OnPath {
param([string]$Dir)
if (-not $Dir) { return $false }
$norm = $Dir.TrimEnd('\').ToLowerInvariant()
foreach ($p in ($env:Path -split ';')) {
if ($p -and ($p.TrimEnd('\').ToLowerInvariant() -eq $norm)) { return $true }
}
return $false
}

$scriptDir = Get-AimScriptDir -PythonCmd $pythonCmd

if (Test-OnPath $scriptDir) {
Write-Host "[+] 'aim' is on your PATH - you can run it directly." -ForegroundColor Green
}
elseif ($scriptDir) {
Write-Host "[!] The 'aim' command was installed to:" -ForegroundColor Yellow
Write-Host " $scriptDir" -ForegroundColor Yellow
Write-Host " but this folder is NOT on your PATH, so typing 'aim' won't work yet." -ForegroundColor Yellow
Write-Host ""

$doAdd = $false
$canPrompt = -not [Console]::IsInputRedirected
if ($canPrompt) {
try {
$answer = Read-Host "Add this folder to your user PATH now? [Y/n]"
$answer = "$answer".Trim()
if ($answer -eq '' -or $answer -match '^(y|yes)$') { $doAdd = $true }
} catch {
$canPrompt = $false
}
}
if (-not $canPrompt) {
Write-Host "[*] Non-interactive session detected; not changing PATH automatically." -ForegroundColor DarkGray
}

if ($doAdd) {
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
$already = $false
if ($userPath) {
foreach ($p in ($userPath -split ';')) {
if ($p -and ($p.TrimEnd('\').ToLowerInvariant() -eq $scriptDir.TrimEnd('\').ToLowerInvariant())) {
$already = $true; break
}
}
}
if (-not $already) {
$newPath = if ([string]::IsNullOrEmpty($userPath)) { $scriptDir } else { ($userPath.TrimEnd(';') + ';' + $scriptDir) }
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
Write-Host "[+] Added to your user PATH." -ForegroundColor Green
} else {
Write-Host "[+] Already present in your user PATH." -ForegroundColor Green
}
# Update the current window too, so 'aim' works right away here.
$env:Path = "$env:Path;$scriptDir"
Write-Host "[+] Updated PATH for THIS window. Open a NEW terminal for it to apply everywhere." -ForegroundColor Green
} else {
Write-Host ""
Write-Host "To add it later, paste this into PowerShell:" -ForegroundColor Cyan
Write-Host " `$d = '$scriptDir'" -ForegroundColor White
Write-Host " [Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','User').TrimEnd(';') + ';' + `$d, 'User')" -ForegroundColor White
Write-Host " # then close and reopen your terminal" -ForegroundColor DarkGray
Write-Host ""
Write-Host "Or run AIM without touching PATH:" -ForegroundColor Cyan
Write-Host " $pythonCmd -m aim.aim_cli init" -ForegroundColor White
}
}
else {
Write-Host "[!] Could not locate the 'aim' executable automatically." -ForegroundColor Yellow
Write-Host " You can still run it with: $pythonCmd -m aim.aim_cli init" -ForegroundColor White
}

Write-Host ""
Write-Host "Get started:" -ForegroundColor Cyan
Write-Host " aim init # run inside your project directory" -ForegroundColor White
Write-Host " aim --help" -ForegroundColor White
Write-Host "========================================="
102 changes: 100 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,104 @@ echo ""
echo "========================================="
echo " [+] AIM installed successfully! "
echo "========================================="
echo "You can now run 'aim' command directly from your terminal."
echo "Run 'aim init' in your project directory to get started."

# 4. Make sure the 'aim' command is reachable. pip often installs console
# scripts into a folder (e.g. ~/.local/bin) that is not on PATH, which is
# why 'aim' can be "command not found" right after install. Locate it and
# optionally add it to PATH. From here on, don't abort on minor errors -
# the install itself already succeeded.
set +e

# Find the folder where the 'aim' executable landed.
AIM_DIR=""
if command -v aim &>/dev/null; then
AIM_DIR="$(dirname "$(command -v aim)")"
else
CANDIDATES="$($PYTHON_CMD -c 'import sysconfig
seen = []
try:
seen.append(sysconfig.get_paths("posix_user")["scripts"])
except Exception:
pass
try:
seen.append(sysconfig.get_path("scripts"))
except Exception:
pass
print("\n".join([p for p in seen if p]))')"
while IFS= read -r d; do
[ -z "$d" ] && continue
if [ -x "$d/aim" ]; then AIM_DIR="$d"; break; fi
[ -z "$AIM_DIR" ] && AIM_DIR="$d"
done <<< "$CANDIDATES"
fi

# Is AIM_DIR already on PATH?
on_path() {
case ":$PATH:" in
*":$1:"*) return 0 ;;
*) return 1 ;;
esac
}

if [ -z "$AIM_DIR" ]; then
echo "[!] Could not locate the 'aim' executable automatically."
echo " You can still run it with: $PYTHON_CMD -m aim.aim_cli init"
elif on_path "$AIM_DIR"; then
echo "[+] 'aim' is on your PATH - you can run it directly."
else
echo "[!] The 'aim' command was installed to:"
echo " $AIM_DIR"
echo " but this folder is NOT on your PATH, so typing 'aim' won't work yet."
echo ""

# Pick the right shell startup file.
SHELL_NAME="$(basename "${SHELL:-bash}")"
case "$SHELL_NAME" in
zsh) RC_FILE="$HOME/.zshrc" ;;
bash)
if [ "$(uname)" = "Darwin" ]; then RC_FILE="$HOME/.bash_profile"; else RC_FILE="$HOME/.bashrc"; fi
;;
*) RC_FILE="$HOME/.profile" ;;
esac

DO_ADD="n"
# Open the real terminal on fd 3. This both tests interactivity and lets us
# read the answer even when the script itself arrived via `curl | bash`
# (where stdin is the pipe, not the keyboard). If /dev/tty can't be opened
# we are non-interactive: do NOT touch PATH, just print instructions.
if { exec 3</dev/tty; } 2>/dev/null; then
printf "Add this folder to your PATH in %s now? [Y/n] " "$RC_FILE"
read -r ANSWER <&3 || ANSWER=""
exec 3<&-
case "$ANSWER" in
""|[Yy]|[Yy][Ee][Ss]) DO_ADD="y" ;;
esac
else
echo "[*] Non-interactive session detected; not changing PATH automatically."
fi

if [ "$DO_ADD" = "y" ]; then
if [ -f "$RC_FILE" ] && grep -Fq "$AIM_DIR" "$RC_FILE"; then
echo "[+] $RC_FILE already references this folder."
else
printf '\n# Added by AIM installer\nexport PATH="$PATH:%s"\n' "$AIM_DIR" >> "$RC_FILE"
echo "[+] Added to $RC_FILE"
fi
export PATH="$PATH:$AIM_DIR"
echo "[+] Updated PATH for this session."
echo " Open a new terminal, or run: source $RC_FILE"
else
echo ""
echo "To add it later, run:"
echo " echo 'export PATH=\"\$PATH:$AIM_DIR\"' >> $RC_FILE && source $RC_FILE"
echo ""
echo "Or run AIM without changing PATH:"
echo " $PYTHON_CMD -m aim.aim_cli init"
fi
fi

echo ""
echo "Get started:"
echo " aim init # run inside your project directory"
echo " aim --help"
echo "========================================="
Loading