This commit is contained in:
@@ -0,0 +1,527 @@
|
||||
# Architecture: `pos ai alias` — AI Agent Alias Manager
|
||||
|
||||
**Date:** 2026-08-26
|
||||
**Author:** Architect (big-pickle)
|
||||
**Status:** DECISION_READY
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
| Decision | Choice |
|
||||
|----------|--------|
|
||||
| Storage | `~/.config/linux_post_install/ai-aliases.env` (pipe-delimited structured data) |
|
||||
| Shell aliases | `~/.config/linux_post_install/ai-aliases.sh` (generated, never hand-edited) |
|
||||
| Tool | `bin/pos-ai-alias` — new `ai` category tool |
|
||||
| No POS_CONFIG scope | Alias management is CRUD, not env-key editing; `pos config` is not involved |
|
||||
| Source of truth | `.env` file; `.sh` file is regenerated on every write |
|
||||
| .bashrc integration | One conditional `source` line, added by postinstall.sh |
|
||||
| INSTALL_CHANGES | `postinstall.sh` adds `.bashrc` source line; `bin/pos` adds `ai-alias` to INTERACTIVE_CMDS |
|
||||
|
||||
**Open items:**
|
||||
- None — all decisions are evidence-backed from project conventions.
|
||||
|
||||
---
|
||||
|
||||
## Decision 1: Data Format
|
||||
|
||||
**Problem:** Store named AI aliases (provider, session name, system prompt) durably, with safe special-character handling and trivial parsing.
|
||||
|
||||
### Options Considered
|
||||
|
||||
**Option A: Shell alias format (one-liner shell aliases)**
|
||||
```
|
||||
alias devbot='pos ai gemini ask --session devbot --system "You are a dev assistant"'
|
||||
```
|
||||
- Architecture: Store raw shell alias lines; `.bashrc` sources the file directly.
|
||||
- Advantages: No generation step; shell sources it natively.
|
||||
- Costs: Parsing aliases back into components (for edit/list) requires fragile quote-aware shell parsing; single quotes inside system prompts break the syntax.
|
||||
- Risks: Prompt containing `'` corrupts the file. Edit must read then reconstruct — fragile.
|
||||
|
||||
**Option B: Pipe-delimited structured data + generated .sh**
|
||||
```
|
||||
devbot|gemini|devbot|You are a dev assistant
|
||||
```
|
||||
- Architecture: `.env` file is the source of truth (pipe-delimited fields). A separate `.sh` file is regenerated from it on every write. `.bashrc` sources the `.sh` file.
|
||||
- Advantages: Parsing is trivial (`IFS='|'`); single-quote escaping is handled at generation time; data is safe to `grep`/`sort`/`awk`.
|
||||
- Costs: One extra file (`.sh`); a `_regen_aliases()` helper function.
|
||||
- Risks: Generation must escape correctly — but this is a single, testable function.
|
||||
|
||||
**Option C: Individual env files per alias**
|
||||
```
|
||||
~/.config/linux_post_install/ai-aliases/devbot.env
|
||||
```
|
||||
- Architecture: One file per alias; load all at shell startup.
|
||||
- Advantages: No parsing of multi-entry files.
|
||||
- Costs: Directory management; glob at shell startup; harder to list all; no atomic operations.
|
||||
|
||||
### Decision: Option B
|
||||
|
||||
Pipe-delimited structured data is the cleanest separation. The `.env` file is the source of truth. The `.sh` file is a generated artifact. This matches the project's own pattern of "generated code between GEN markers" — except here the generator lives inside the tool itself, not `make gen`.
|
||||
|
||||
**Rationale:** The project already has a pattern of generated files (e.g., `GEN:START`/`GEN:END` blocks, `completions/pos.bash`). The tool owns its own generation. Parsing shell aliases is fragile and error-prone; pipe-delimited data is trivially safe.
|
||||
|
||||
### Data Format Specification
|
||||
|
||||
```
|
||||
# ~/.config/linux_post_install/ai-aliases.env
|
||||
# Managed by: pos ai alias (do not hand-edit)
|
||||
# Format: alias_name|provider|session_name|system_prompt
|
||||
# Pipe characters in system_prompt are not supported.
|
||||
#
|
||||
# agent_name|provider|session_name|system_prompt
|
||||
devbot|gemini|devbot|You are a Linux dev assistant. Reply with commands only.
|
||||
code|openrouter|codereview|You are a code reviewer. Be concise.
|
||||
```
|
||||
|
||||
**Field constraints:**
|
||||
|
||||
| Field | Rules |
|
||||
|-------|-------|
|
||||
| `alias_name` | Shell-valid identifier: `[a-zA-Z][a-zA-Z0-9_-]*` |
|
||||
| `provider` | Must match an installed provider: `gemini`, `openrouter`, etc. |
|
||||
| `session_name` | Defaults to the alias name if empty; `[a-zA-Z0-9_-]+` |
|
||||
| `system_prompt` | Free text; no `\|` (pipe) characters; may be empty (uses built-in prompt) |
|
||||
|
||||
**Header:** Two comment lines at the top (file description + format) are auto-maintained by the tool.
|
||||
|
||||
**Empty session_name convention:** When session_name is empty (field is blank between pipes), the alias uses the alias name as the session name. This avoids redundant repetition for the common case.
|
||||
|
||||
---
|
||||
|
||||
## Decision 2: File Layout
|
||||
|
||||
### New files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `bin/pos-ai-alias` | New CLI tool (100755) |
|
||||
|
||||
### Modified files
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `bin/pos` | Add `ai-alias` to `INTERACTIVE_CMDS` list |
|
||||
| `postinstall.sh` | Add `.bashrc` source line for `ai-aliases.sh` (conditional, no-clobber) |
|
||||
|
||||
### Runtime files (user config, NOT in repo)
|
||||
|
||||
| File | Purpose | Mutability |
|
||||
|------|---------|------------|
|
||||
| `~/.config/linux_post_install/ai-aliases.env` | Alias data (source of truth) | Created/modified by tool |
|
||||
| `~/.config/linux_post_install/ai-aliases.sh` | Generated shell aliases | Regenerated on every write |
|
||||
|
||||
### Files NOT modified
|
||||
|
||||
| File | Why not |
|
||||
|------|---------|
|
||||
| `.gitignore` | `~/.config/linux_post_install/` is a user directory, not in the repo. No new repo files to ignore. |
|
||||
| `config/` | No template file needed — the env file is user-created on first use. |
|
||||
| `lib/` | No new library. Tool sources `common.sh` + `menu-lib.sh` from existing libs. |
|
||||
|
||||
---
|
||||
|
||||
## Decision 3: Tool Interface
|
||||
|
||||
### POS Header
|
||||
|
||||
```bash
|
||||
# POS: ai alias — Create/edit/remove named AI agent aliases
|
||||
# POS_SUBCMDS: create edit remove list show
|
||||
```
|
||||
|
||||
No `POS_FLAGS:` — this is a subcommand-based tool, not a flag-based tool.
|
||||
|
||||
### CLI Interface
|
||||
|
||||
```
|
||||
pos ai alias [subcommand] [args]
|
||||
|
||||
Subcommands:
|
||||
(no args) Interactive menu (create/edit/remove/list)
|
||||
create Create a new alias (interactive prompts)
|
||||
create <name> Create with given name (interactive prompts for rest)
|
||||
edit Pick an alias to edit (interactive)
|
||||
edit <name> Edit a specific alias
|
||||
remove Pick an alias to remove (interactive, with confirmation)
|
||||
remove <name> Remove a specific alias (with confirmation)
|
||||
list List all aliases (non-interactive, machine-readable)
|
||||
show <name> Show one alias's details
|
||||
|
||||
Options:
|
||||
-h|--help Show this help.
|
||||
|
||||
Examples:
|
||||
pos ai alias # interactive menu
|
||||
pos ai alias list # show all aliases
|
||||
pos ai alias create # interactive create
|
||||
pos ai alias create mybot # create 'mybot' alias
|
||||
pos ai alias edit mybot # edit the 'mybot' alias
|
||||
pos ai alias remove mybot # remove 'mybot' (with confirm)
|
||||
pos ai alias show mybot # show alias details
|
||||
```
|
||||
|
||||
### Subcommand Details
|
||||
|
||||
**`pos ai alias` (no args):** Interactive menu using `menu_run` from `lib/menu-lib.sh`. Options:
|
||||
1. Create new alias
|
||||
2. Edit existing alias
|
||||
3. Remove alias
|
||||
4. List aliases
|
||||
|
||||
**`pos ai alias list`:** Non-interactive table output:
|
||||
```
|
||||
Aliases (3):
|
||||
mybot gemini mybot You are a helpful assistant
|
||||
code openrouter code You are a code reviewer
|
||||
dev gemini devbot Dev assistant
|
||||
```
|
||||
Format: `%-12s %-12s %-12s %s` (name, provider, session, prompt-truncated-to-60).
|
||||
|
||||
**`pos ai alias show <name>`:** Full details including the resolved shell command.
|
||||
|
||||
---
|
||||
|
||||
## Decision 4: POS_CONFIG
|
||||
|
||||
**Decision: NO POS_CONFIG scope.**
|
||||
|
||||
**Rationale:** The `pos config` / `POS_CONFIG` system is designed for simple `KEY=VALUE` env files (like `ai.env`, `telegram.env`, `entertainment.env`). Aliases are structured, multi-field records, not key-value pairs. The `cfg_ui()` pattern from `lib/config-ui.sh` doesn't apply here — it renders a numbered menu of KEY=VALUE pairs, not CRUD operations on named records.
|
||||
|
||||
The alias tool is self-contained with its own interactive menus. It does not participate in `pos config`.
|
||||
|
||||
---
|
||||
|
||||
## Decision 5: Shell Alias Generation
|
||||
|
||||
### The `_regen_aliases()` function
|
||||
|
||||
This function reads `ai-aliases.env` and writes `ai-aliases.sh`:
|
||||
|
||||
```bash
|
||||
_regen_aliases() {
|
||||
local env_file="$1" sh_file="$2" tmp
|
||||
tmp="$(mktemp)"
|
||||
printf '#!/usr/bin/env bash\n# Auto-generated by pos ai alias — do not hand-edit.\n# Source: %s\n\n' "$env_file" >"$tmp"
|
||||
|
||||
if [ -f "$env_file" ]; then
|
||||
while IFS='|' read -r name provider session prompt _rest; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$name" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "$name" ]] && continue
|
||||
|
||||
# Validate alias name
|
||||
[[ "$name" =~ ^[a-zA-Z][a-zA-Z0-9_-]*$ ]] || continue
|
||||
|
||||
# Session defaults to alias name if empty
|
||||
[ -z "$session" ] && session="$name"
|
||||
|
||||
# Escape single quotes in the system prompt for shell-safe embedding
|
||||
local escaped_prompt="${prompt//\'/\'\\\'\'}"
|
||||
|
||||
printf "alias %s='pos ai %s ask --session %s" "$name" "$provider" "$session" >>"$tmp"
|
||||
if [ -n "$prompt" ]; then
|
||||
printf " --system '%s'" "$escaped_prompt" >>"$tmp"
|
||||
fi
|
||||
printf "'\n" >>"$tmp"
|
||||
done < <(grep -v '^[[:space:]]*#' "$env_file" | grep -v '^[[:space:]]*$' || true)
|
||||
fi
|
||||
|
||||
mv "$tmp" "$sh_file"
|
||||
chmod 644 "$sh_file"
|
||||
}
|
||||
```
|
||||
|
||||
**Single-quote escaping:** `${prompt//\'/\'\\\'\'}` — bash `parameter expansion` replaces every `'` with `'\''` (close-quote, escaped-quote, open-quote). This is the standard and safe pattern for embedding arbitrary strings in single-quoted shell contexts.
|
||||
|
||||
**Edge case — empty prompt:** When the system prompt is empty, the `--system` flag is omitted entirely, letting `pos ai` use its built-in default prompt.
|
||||
|
||||
### Syntax validation before commit
|
||||
|
||||
After generating the `.sh` file, run `bash -n` to verify syntax:
|
||||
```bash
|
||||
if ! bash -n "$sh_file" 2>/dev/null; then
|
||||
warn "Generated alias file has syntax errors — keeping previous version"
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Shell integration in .bashrc
|
||||
|
||||
```bash
|
||||
# AI aliases (managed by pos ai alias)
|
||||
[ -f ~/.config/linux_post_install/ai-aliases.sh ] && source ~/.config/linux_post_install/ai-aliases.sh
|
||||
```
|
||||
|
||||
This line is added by `postinstall.sh` with the standard no-clobber grep check.
|
||||
|
||||
---
|
||||
|
||||
## Decision 6: Interactive Flow
|
||||
|
||||
### Main Menu (`pos ai alias` — no args)
|
||||
|
||||
Uses `menu_run` from `lib/menu-lib.sh`:
|
||||
|
||||
```
|
||||
════════════════════════════════════════════
|
||||
AI Agent Aliases
|
||||
════════════════════════════════════════════
|
||||
1) Create new alias
|
||||
2) Edit existing alias
|
||||
3) Remove alias
|
||||
4) List aliases
|
||||
0) Exit
|
||||
----------------------------------------
|
||||
Choose:
|
||||
```
|
||||
|
||||
### Create Flow
|
||||
|
||||
1. Prompt for alias name: `menu_ask_value "Alias name" ""` — validate format (`[a-zA-Z][a-zA-Z0-9_-]*`)
|
||||
2. Check for duplicate name → warn and re-prompt if taken
|
||||
3. Prompt for provider: show available providers (read from `$PROVIDER_DIR/*.sh`), default `gemini`
|
||||
4. Prompt for session name: default = alias name
|
||||
5. Prompt for system prompt: default = empty (uses built-in)
|
||||
6. Confirm: `confirm "Create alias '<name>'?" y`
|
||||
7. Write to `.env`, regenerate `.sh`, log success
|
||||
|
||||
### Edit Flow
|
||||
|
||||
1. List existing aliases (name + provider + first-40-chars of prompt)
|
||||
2. Pick one (if no arg given): `menu_pick "Pick alias" "${names[@]}"`
|
||||
3. Show current values
|
||||
4. For each field, prompt with current value as default (Enter = keep)
|
||||
5. Confirm changes
|
||||
6. Rewrite `.env` entry, regenerate `.sh`
|
||||
|
||||
### Remove Flow
|
||||
|
||||
1. Pick alias: `menu_pick` or named
|
||||
2. Show alias details
|
||||
3. `confirm "Remove alias '<name>'? This cannot be undone." n` (default = no)
|
||||
4. Remove from `.env`, regenerate `.sh`
|
||||
|
||||
### List Flow (non-interactive)
|
||||
|
||||
Prints formatted table to stdout. Provider column left-aligned, name left-aligned, prompt truncated to 60 chars with `...`.
|
||||
|
||||
### Show Flow (non-interactive)
|
||||
|
||||
Full details + resolved command:
|
||||
```
|
||||
Alias: mybot
|
||||
Provider: gemini
|
||||
Session: mybot
|
||||
Prompt: You are a helpful assistant
|
||||
Command: pos ai gemini ask --session mybot --system 'You are a helpful assistant'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Decision 7: Edge Cases and Error Handling
|
||||
|
||||
| Edge Case | Handling |
|
||||
|-----------|----------|
|
||||
| **Duplicate alias name on create** | `warn "Alias '$name' already exists — use 'pos ai alias edit $name' instead"`; re-prompt |
|
||||
| **Empty alias name** | `err "Alias name cannot be empty"` |
|
||||
| **Invalid alias name** (contains spaces, starts with digit) | `err "Invalid alias name '$name' — use letters, digits, hyphens, underscores"` |
|
||||
| **Invalid provider** | `err "Unknown provider '$p' — available: $(ls ...)"` — uses same provider discovery as `pos-ai` |
|
||||
| **Empty system prompt** | Allowed — omit `--system` flag; `pos ai` uses its built-in default prompt |
|
||||
| **Very long system prompt** | Truncate display in `list` output (60 chars + `...`); full value preserved in `.env` and `.sh`. Warn if > 500 chars during creation. |
|
||||
| **Pipe character in system prompt** | Rejected on input: `err "System prompt must not contain '\|' characters"` |
|
||||
| **System prompt with single quotes** | Handled by `_regen_aliases()` escaping: `'` -> `'\''` in the generated alias line |
|
||||
| **Editing an alias "in use"** | No lock/detection needed. The user edits the `.env`; on next shell startup (or `source ~/.bashrc`), aliases update. No runtime state conflict. |
|
||||
| **File doesn't exist yet** | First create auto-creates both `.env` and `.sh` |
|
||||
| **Corrupted/invalid .env line** | Skipped by `_regen_aliases()` (name validation regex) |
|
||||
| **Concurrent edits** | Not a concern — personal single-user tool. Last write wins. |
|
||||
| **Missing pos-ai dependency** | Tool doesn't require `pos-ai` at runtime — it only writes config. No dep guard needed. |
|
||||
|
||||
---
|
||||
|
||||
## Decision 8: Security Considerations
|
||||
|
||||
### System prompt injection
|
||||
|
||||
System prompts are user-authored text that becomes a shell argument. Risks:
|
||||
- **Shell injection via alias execution:** The prompt is single-quoted in the alias, so shell metacharacters (`$`, backtick, `!`) are literal — safe.
|
||||
- **`pos ai` prompt injection:** This is a user's own prompt for their own AI. No trust boundary crossing.
|
||||
- **File permissions:** `ai-aliases.env` gets `chmod 600` (user-only read; consistent with other config files). `ai-aliases.sh` gets `chmod 644` (needed by bash `source`).
|
||||
|
||||
### Escaping correctness
|
||||
|
||||
The single-quote escaping `${prompt//\'/\'\\\'\'}` is the only place where correctness matters critically. If it fails, the generated alias has a syntax error and `source` will report it. Mitigation:
|
||||
- The tool runs `bash -n` on the generated `.sh` file before committing it.
|
||||
- If syntax check fails, warn and skip the regeneration (keep the old `.sh`).
|
||||
|
||||
### No secrets in the alias file
|
||||
|
||||
System prompts are not secrets — they're user-authored instructions. API keys stay in `ai.env` (already managed by `pos config ai`). No new secret surface.
|
||||
|
||||
---
|
||||
|
||||
## Decision 9: Integration with pos-ai
|
||||
|
||||
### How aliases invoke pos-ai
|
||||
|
||||
Each generated alias calls:
|
||||
```bash
|
||||
alias <name>='pos ai <provider> ask --session <session> --system "<prompt>"'
|
||||
```
|
||||
|
||||
This uses the existing `pos-ai` flags:
|
||||
- `--provider <name>` — supported since the beginning (line 633 of `bin/pos-ai`)
|
||||
- `--session <name>` — supported (line 639)
|
||||
- `--system <text>` — supported (line 642)
|
||||
|
||||
**No changes to `bin/pos-ai` are required.** The alias tool is a standalone configuration tool that writes shell aliases calling `pos ai`.
|
||||
|
||||
### Provider validation
|
||||
|
||||
The alias tool must validate the provider name against installed providers. It reuses the same discovery logic from `pos-ai`:
|
||||
```bash
|
||||
PROVIDER_DIR="$(dirname "$0")/../lib/ai-providers"
|
||||
# Fallback for installed layout
|
||||
[ -d "$PROVIDER_DIR" ] || PROVIDER_DIR="$(dirname "$0")/ai-providers"
|
||||
```
|
||||
|
||||
This is the same pattern used in `pos-ai` at line 17-18. The alias tool discovers providers independently (no dependency on `pos-ai` being sourced).
|
||||
|
||||
---
|
||||
|
||||
## Decision 10: Installation Changes
|
||||
|
||||
### postinstall.sh modification
|
||||
|
||||
Add a block after the existing `ai.env` installation (around line 50):
|
||||
|
||||
```bash
|
||||
# ── AI aliases shell integration ───────────────────────────────
|
||||
ALIAS_SRC_LINE='# AI aliases (managed by pos ai alias)
|
||||
[ -f ~/.config/linux_post_install/ai-aliases.sh ] && source ~/.config/linux_post_install/ai-aliases.sh'
|
||||
if ! grep -qsF "ai-aliases.sh" "$BASHRC" 2>/dev/null; then
|
||||
run printf '%s\n' "$ALIAS_SRC_LINE" >> "$BASHRC"
|
||||
log "Added AI aliases source to ~/.bashrc"
|
||||
fi
|
||||
```
|
||||
|
||||
### bin/pos modification
|
||||
|
||||
Add `ai-alias` to the `INTERACTIVE_CMDS` list (line 262). Current value:
|
||||
```
|
||||
INTERACTIVE_CMDS="docker-compose docker-vbox network-hotspot system-firewall media-mp4 media-sync system-backup system-uninstall share-usb-server share-smb-server share-smb-client share-nfs-client share-nfs-server communication-telegram-listener communication-matrix-listener ai ai-gemini ai-openrouter system-schedule entertainment-config config"
|
||||
```
|
||||
|
||||
Add `ai-alias` to this space-separated list.
|
||||
|
||||
### No other installation changes
|
||||
|
||||
- No new apt packages (no deps beyond bash)
|
||||
- No new lib files (tool sources `common.sh` + `menu-lib.sh` from existing libs)
|
||||
- No systemd services
|
||||
- No config template in `config/`
|
||||
|
||||
---
|
||||
|
||||
## Decision 11: Long Prompt Handling
|
||||
|
||||
System prompts can be arbitrarily long. Shell aliases have a practical limit (ARG_MAX, typically 2MB on Linux), so this is not a hard constraint. However:
|
||||
|
||||
- **Display:** `list` output truncates to 60 chars + `...`
|
||||
- **Storage:** Full prompt in `.env` and `.sh` — no truncation
|
||||
- **Interactive edit:** Shows full current value, allows full editing
|
||||
- **Warning:** During creation, if prompt exceeds 500 chars: `warn "System prompt is long (${#prompt} chars) — consider keeping it concise"`
|
||||
|
||||
**Decision:** No artificial length limit.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Core tool (single commit)
|
||||
|
||||
1. Create `bin/pos-ai-alias` with:
|
||||
- Shebang, strict mode, `common.sh` source, `menu-lib.sh` source
|
||||
- `# POS:` header + `# POS_SUBCMDS:`
|
||||
- `CONFIG_FILE` and `ALIASES_SH_FILE` path constants
|
||||
- `_load_aliases()` — reads `.env` into parallel arrays (names, providers, sessions, prompts)
|
||||
- `_find_alias()` — lookup by name, returns index
|
||||
- `_write_env_file()` — writes entire `.env` from arrays
|
||||
- `_regen_aliases()` — reads `.env`, writes `.sh` with proper escaping
|
||||
- `_list_aliases()` — non-interactive table output
|
||||
- `_show_alias()` — non-interactive single alias details
|
||||
- `_create_alias()` — interactive create with validation
|
||||
- `_edit_alias()` — interactive edit with field-level prompts
|
||||
- `_remove_alias()` — interactive remove with confirm
|
||||
- `_main_menu()` — interactive menu via `menu_run`
|
||||
- Subcommand dispatch (`case` pattern)
|
||||
- `usage()` function
|
||||
2. Add `ai-alias` to `INTERACTIVE_CMDS` in `bin/pos`
|
||||
3. Add `.bashrc` source line to `postinstall.sh`
|
||||
|
||||
### Phase 2: Verification
|
||||
|
||||
1. `chmod +x bin/pos-ai-alias`
|
||||
2. `bash -n bin/pos-ai-alias`
|
||||
3. `make gen` — regenerate tables (new tool appears in dispatch table, bin tree, file table)
|
||||
4. `make check` — self-consistency gate
|
||||
5. `make lint` — convention gate (0 FAIL, 0 WARN)
|
||||
6. Manual test: create, list, show, edit, remove aliases; verify `.sh` file is correct
|
||||
7. Source `.bashrc` and verify aliases work
|
||||
|
||||
### Phase 3: Documentation
|
||||
|
||||
1. `DOC/POS.md` — add `ai alias` section (hand-written)
|
||||
2. `DOC/HOWTO.md` — add index row
|
||||
3. `DOC/howto/ai.md` — add aliases section (if ai.md exists; otherwise add to existing ai howto)
|
||||
4. `DOC/AGENT_Context_Project.md` — regenerated by `make gen`; hand-add to Common Tasks table
|
||||
5. Update `AGENT_TODO.md` Done section (dated)
|
||||
|
||||
---
|
||||
|
||||
## Architectural Constraints
|
||||
|
||||
1. **Tool must source `lib/common.sh`** via the fallback chain (not self-contained)
|
||||
2. **Tool must source `lib/menu-lib.sh`** for interactive menus
|
||||
3. **Tool MUST be in `INTERACTIVE_CMDS`** in `bin/pos`
|
||||
4. **Generated `.sh` file must pass `bash -n`** before commit
|
||||
5. **Env-seam:** all file paths use `${CONFIG_DIR:-...}` pattern (already in `common.sh`)
|
||||
6. **`chmod 600`** for `.env`, `chmod 644` for `.sh`
|
||||
7. **No dependency on `pos-ai`** being installed — tool writes config, doesn't run `pos ai`
|
||||
8. **Pipe delimiter** — system prompts must not contain `|`; validated on input
|
||||
|
||||
---
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] `bash -n bin/pos-ai-alias` passes
|
||||
- [ ] `shellcheck bin/pos-ai-alias` passes (or only known false positives)
|
||||
- [ ] `make gen` regenerates tables correctly
|
||||
- [ ] `make check` passes (bash -n, exec bits, doc sync, smoke)
|
||||
- [ ] `make lint` passes (0 FAIL, 0 WARN)
|
||||
- [ ] `pos ai alias --help` shows help
|
||||
- [ ] `pos ai alias` shows interactive menu
|
||||
- [ ] Create -> list -> show -> edit -> remove cycle works
|
||||
- [ ] Generated `.sh` file has correct alias syntax
|
||||
- [ ] `bash -n` on generated `.sh` passes
|
||||
- [ ] `.bashrc` source line works (aliases available after source)
|
||||
- [ ] Special chars in system prompt (single quotes, spaces, $) survive round-trip
|
||||
- [ ] Duplicate name is rejected
|
||||
- [ ] Invalid alias name is rejected
|
||||
- [ ] Invalid provider is rejected
|
||||
|
||||
---
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
| Risk | Likelihood | Impact | Mitigation |
|
||||
|------|------------|--------|------------|
|
||||
| Single-quote escaping fails for exotic prompts | Low | High (syntax error in .sh) | `bash -n` check before commit; warn + skip on failure |
|
||||
| User has many aliases -> list becomes long | Low | Low | `menu_pick` already supports filtering |
|
||||
| `.bashrc` source line conflicts with existing alias definitions | Very Low | Medium | Grep-check before adding; line is a conditional source, not an alias definition |
|
||||
| `make lint` rejects the new tool for a convention violation | Low | Low (blocking) | Follow template exactly; deps guards before help; proper header |
|
||||
|
||||
---
|
||||
|
||||
**End of architecture document.**
|
||||
Reference in New Issue
Block a user