Compare commits

..

6 Commits

Author SHA1 Message Date
Your Name d84a35efce fix: read -e -i stores into variable directly, not stdout
gates / consistency-and-conventions (push) Successful in 2m34s
edited="\$(read ...)" was always empty because read writes to a variable
name, not stdout. Changed to: read -e -p "Command: " -i "\$flat" edited
which stores directly into \$edited.
2026-08-26 04:42:18 -04:00
Your Name 9564880ebf fix: AI command edit - flatten multi-line for readline
gates / consistency-and-conventions (push) Successful in 1m47s
read -e -i only handles single-line text. Multi-line commands (docker
install etc) broke it. Now flattens newlines to spaces before pre-filling
the readline buffer. User sees a single editable line.
2026-08-26 04:37:52 -04:00
Your Name d0299d3f98 feat: AI command edit via clipboard + xdotool fallback
gates / consistency-and-conventions (push) Successful in 2m14s
- _inject_command tries: xclip/wl-copy (clipboard) -> xdotool (typing) -> tmux -> history
- Clipboard is primary: user pastes with Ctrl+Shift+V
- preinstall.sh: add xdotool and xclip to PACKAGES
2026-08-26 04:13:36 -04:00
Your Name c1f1c4109f feat: AI command prompt adds e(dit) option with keyboard simulation
gates / consistency-and-conventions (push) Successful in 2m11s
- e: xdotool type (X11/Wayland) -> tmux send-keys -> history fallback
- Command appears on active terminal line for editing before Enter
- Y/Enter: execute, n: add to history
2026-08-26 03:51:16 -04:00
Your Name 710b626f47 feat: AI command prompt - run or edit detected shell commands
gates / consistency-and-conventions (push) Successful in 2m6s
- _extract_commands() parses bash/sh/shell fenced code blocks
- _prompt_run_command() prompts [Y/n] via /dev/tty after AI response
- Y/Enter: execute via run helper (respects DRY_RUN)
- n: command added to history (press up-arrow to recall, edit, run)
- Integrated in both cmd_ask() and cmd_chat()
- Skipped when output is piped/redirected
2026-08-26 03:26:11 -04:00
Your Name 1c19c0de59 fix: _cfg_provider_keys path resolution for installed layout
gates / consistency-and-conventions (push) Successful in 1m47s
Try both repo (../lib/ai-providers/) and installed (./ai-providers/) paths.
Installed layout copies ai-providers/ to same dir as config-ui.sh.
2026-08-26 03:07:29 -04:00
4 changed files with 117 additions and 4 deletions
+1 -1
View File
@@ -633,7 +633,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
| `bin/pos-system-health` | 209 | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL |
| `bin/pos-system-schedule` | 151 | Scheduled jobs: run a command on a timer; notify on threshold/change/error/always or silently |
| `bin/pos-system-uninstall` | 415 | Remove pos toolkit binaries, services, shell integration, config, and data |
| `bin/pos-ai` | 632 | AI assistant: ask, chat, sessions, capture, models, providers |
| `bin/pos-ai` | 735 | AI assistant: ask, chat, sessions, capture, models, providers |
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
| `bin/pos-tree` | 112 | Show the pos CLI command tree: categories, commands, and subcommands |
| `completions/pos.bash` | 306 | Dynamic bash completion |
+103
View File
@@ -353,6 +353,101 @@ render_markdown() {
printf '\n%s\n' "$rendered"
}
# ── Command extraction from AI responses ────────────────────────
_extract_commands() {
local text="$1"
printf '%s' "$text" | awk '
/^```(bash|sh|shell)/ { in_block=1; next }
/^```/ { if (in_block) in_block=0; next }
in_block && NF > 0 { lines[++n] = $0 }
END {
for (i = 1; i <= n; i++) {
if (i > 1) printf "\n"
printf "%s", lines[i]
}
}
'
}
# ── Interactive prompt to run extracted commands ─────────────────
_prompt_run_command() {
local cmd="$1"
# Only prompt on interactive terminals with a controlling tty
[ -w /dev/tty ] || return 0
printf '\n%s\n' "Command detected:" >&2
printf ' %s\n\n' "$cmd" >&2
printf 'Run this command? [Y/n/e(dit)] ' >&2
local choice
IFS= read -r choice </dev/tty || choice=""
case "${choice,,}" in
n|N)
# Add to shell history so user can press ↑ to recall, edit, run
history -s "$cmd" 2>/dev/null || true
printf '%s\n' "Command added to history — press ↑ to recall, edit, and run." >&2
;;
e|E)
_inject_command "$cmd"
;;
*)
# Y or Enter: execute
printf '%s\n' "$cmd"
run eval "$cmd"
;;
esac
}
# Inject command for editing. Priority:
# 1. read -e -i (bash native readline — works in ANY terminal, CLI or GUI)
# 2. Clipboard (xclip/wl-copy — GUI only)
# 3. xdotool typing (X11 GUI only)
# 4. tmux send-keys
# 5. History fallback (press ↑)
_inject_command() {
local cmd="$1"
# Flatten multi-line commands for readline (read -i only handles single line)
local flat
flat="$(printf '%s' "$cmd" | tr '\n' ' ' | sed 's/ */ /g; s/^ //; s/ $//')"
# 1. Bash readline: pre-fill the command on the line, user edits, Enter runs
if [ -w /dev/tty ]; then
local edited=""
printf '\n' >&2
if read -e -p "Command: " -i "$flat" edited </dev/tty 2>/dev/null; then
[ -n "$edited" ] || { printf '%s\n' "Empty command — skipped." >&2; return 0; }
printf '%s\n' "$edited"
run eval "$edited"
return 0
fi
# read failed (Ctrl+C / EOF) — fall through
fi
# 2. Clipboard (GUI only)
local injected=""
if command -v wl-copy >/dev/null 2>&1 && [ -n "${WAYLAND_DISPLAY:-}" ]; then
printf '%s' "$cmd" | wl-copy && injected="wayland"
elif command -v xclip >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
printf '%s' "$cmd" | xclip -selection clipboard && injected="x11"
elif command -v xsel >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
printf '%s' "$cmd" | xsel --clipboard --input && injected="x11"
fi
if [ -n "$injected" ]; then
local key="Ctrl+V"; [ "$injected" = "x11" ] && key="Ctrl+Shift+V"
printf '%s\n' "Command copied to clipboard — paste with $key, edit, Enter to run." >&2
return 0
fi
# 3. xdotool (X11 GUI only)
if command -v xdotool >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
printf '%s' "$cmd" | xdotool type --clearmodifiers --file -
return 0
fi
# 4. tmux
if [ -n "${TMUX:-}" ]; then
tmux send-keys "$cmd"
return 0
fi
# 5. History fallback
history -s "$cmd" 2>/dev/null || true
printf '%s\n' "Command added to history — press ↑ to recall, edit, and run." >&2
}
# ── Machine context appended to the built-in default prompt ─────
mc_clean() {
sed -e 's/\x1b\[[0-9;]*[A-Za-z]//g' \
@@ -471,6 +566,10 @@ cmd_ask() {
messages="$(session_push "$messages" assistant "$out")"
session_save "$messages"
render_markdown "$out"
# Command execution prompt: extract commands from response and offer to run
local _cmd
_cmd="$(_extract_commands "$out")"
[ -n "$_cmd" ] && _prompt_run_command "$_cmd"
}
cmd_chat() {
@@ -504,6 +603,10 @@ cmd_chat() {
session_save "$messages"
printf '\n'
render_markdown "$answer"
# Command execution prompt: extract commands from response and offer to run
local _cmd
_cmd="$(_extract_commands "$answer")"
[ -n "$_cmd" ] && _prompt_run_command "$_cmd"
printf '\n\n'
done
echo
+12 -3
View File
@@ -140,9 +140,18 @@ _cfg_plugin_keys() {
# adapters' "# PROVIDER_CONFIG:" headers (lib/ai-providers/*.sh).
_cfg_provider_keys() {
local pdir line key desc flags
# Find lib/ai-providers/ relative to config-ui.sh
pdir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib/ai-providers" 2>/dev/null && pwd)"
[ -d "$pdir" ] || return 0
# Repo layout: lib/config-ui.sh → ../lib/ai-providers/
# Installed layout: /usr/local/bin/config-ui.sh → ./ai-providers/
pdir=""
for candidate in \
"$(dirname "${BASH_SOURCE[0]}")/../lib/ai-providers" \
"$(dirname "${BASH_SOURCE[0]}")/ai-providers"; do
if [ -d "$candidate" ]; then
pdir="$(cd "$candidate" 2>/dev/null && pwd)"
break
fi
done
[ -n "$pdir" ] || return 0
while IFS= read -r line; do
[ -n "$line" ] || continue
# Format: KEY=flags:description (same as POS_CONFIG key fields)
+1
View File
@@ -39,6 +39,7 @@ PACKAGES=(
python3 python3-pip rclone
ffmpeg
libqrencode4 libgtk-3-0 adb
xdotool xclip
)
spawn "apt update" sudo apt update