Conversation
Pulls cmd_away + cmd_identity + cmd_whois + 7 _identity_* helpers (422 lines combined) out of the airc top-level into lib/airc_bash/cmd_identity.sh. airc: 2711 → 2290 lines (-421) lib/airc_bash/cmd_identity.sh: +448 (422 body + 26 header) The bundle was already cohesive — every helper is _identity_*, every public verb is about presence/persona — so one file rather than three. Verified: identity show / whoami / whois all dispatch correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR continues the Phase 3 bash monolith split by extracting the “identity bundle” (away/identity/whois + _identity_* helpers) out of airc into a dedicated bash module.
Changes:
- Added
lib/airc_bash/cmd_identity.shcontainingcmd_away,cmd_identity,cmd_whois, and identity import/push helpers. - Removed the corresponding identity section from
aircand replaced it with a lib-dir-resolvedsourceof the new module.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| lib/airc_bash/cmd_identity.sh | New extracted module implementing identity/away/whois and related helpers. |
| airc | Replaces inline identity bundle with source lib/airc_bash/cmd_identity.sh via lib-dir resolver. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| --pronouns) pronouns="${2:-}"; set_pronouns=1; shift 2 ;; | ||
| --role) role="${2:-}"; set_role=1; shift 2 ;; | ||
| --bio) bio="${2:-}"; set_bio=1; shift 2 ;; | ||
| --status) status="${2:-}"; set_status=1; shift 2 ;; |
There was a problem hiding this comment.
Flag parsing in _identity_set uses shift 2 for options that take a value. With set -e enabled globally, calling e.g. airc identity set --pronouns (missing value) will cause shift: shift count out of range and exit the whole program instead of producing a friendly usage error. Please explicitly detect a missing value for each flag (or shift safely) and die with a clear message.
| --pronouns) pronouns="${2:-}"; set_pronouns=1; shift 2 ;; | |
| --role) role="${2:-}"; set_role=1; shift 2 ;; | |
| --bio) bio="${2:-}"; set_bio=1; shift 2 ;; | |
| --status) status="${2:-}"; set_status=1; shift 2 ;; | |
| --pronouns) | |
| [ $# -ge 2 ] || die "Missing value for --pronouns" | |
| pronouns="$2"; set_pronouns=1; shift 2 | |
| ;; | |
| --role) | |
| [ $# -ge 2 ] || die "Missing value for --role" | |
| role="$2"; set_role=1; shift 2 | |
| ;; | |
| --bio) | |
| [ $# -ge 2 ] || die "Missing value for --bio" | |
| bio="$2"; set_bio=1; shift 2 | |
| ;; | |
| --status) | |
| [ $# -ge 2 ] || die "Missing value for --status" | |
| status="$2"; set_status=1; shift 2 | |
| ;; |
| local parent self_base prefix sibling | ||
| parent=$(dirname "$AIRC_WRITE_DIR") | ||
| self_base=$(basename "$AIRC_WRITE_DIR") | ||
| # Strip a trailing .<word> to recover the primary prefix. Mirrors the | ||
| # detection in cmd_peers (#124) so .airc / .airc.general both resolve | ||
| # to .airc as the prefix; in tests we see state / state.general → state. | ||
| prefix=$(printf '%s' "$self_base" | sed -E 's/\.[a-z0-9-]+$//') |
There was a problem hiding this comment.
The sibling-scope walk derives prefix via sed -E 's/\.[a-z0-9-]+$//' on the current scope basename. For primary scopes like .airc, this produces an empty prefix (same edge case handled in _primary_scope_for), causing the glob to expand to $parent/.* and potentially scan many unrelated dot-directories. Consider using _primary_scope_for "$AIRC_WRITE_DIR" (or replicating its empty-prefix guard) to ensure .airc/.airc.<room> resolve correctly and efficiently.
| local parent self_base prefix sibling | |
| parent=$(dirname "$AIRC_WRITE_DIR") | |
| self_base=$(basename "$AIRC_WRITE_DIR") | |
| # Strip a trailing .<word> to recover the primary prefix. Mirrors the | |
| # detection in cmd_peers (#124) so .airc / .airc.general both resolve | |
| # to .airc as the prefix; in tests we see state / state.general → state. | |
| prefix=$(printf '%s' "$self_base" | sed -E 's/\.[a-z0-9-]+$//') | |
| local parent primary_scope prefix sibling | |
| parent=$(dirname "$AIRC_WRITE_DIR") | |
| # Normalize to the primary scope first so primary scopes like .airc | |
| # do not collapse to an empty prefix; sidecars like .airc.general | |
| # still resolve to .airc for the sibling walk. | |
| primary_scope=$(_primary_scope_for "$AIRC_WRITE_DIR") | |
| prefix=$(basename "$primary_scope") |
| # Args: name, identity-json, host (any may be empty). | ||
| _whois_pretty() { | ||
| local name="$1" blob="${2:-{\}}" host="${3:-}" | ||
| NAME="$name" BLOB="$blob" HOST="$host" python3 <<'PYEOF' |
There was a problem hiding this comment.
_whois_pretty invokes python3 directly. On Git Bash/Windows (and any environment where AIRC_PYTHON=python but python3 is not on PATH), airc whois will fail even though startup already resolved a working interpreter into $AIRC_PYTHON. Use $AIRC_PYTHON here for consistency and cross-platform behavior.
| NAME="$name" BLOB="$blob" HOST="$host" python3 <<'PYEOF' | |
| NAME="$name" BLOB="$blob" HOST="$host" "$AIRC_PYTHON" <<'PYEOF' |
| # cmd_kick extracted to lib/airc_bash/cmd_kick.sh | ||
| # (#152 Phase 3 file split). Host-only peer eviction lives in its own | ||
| # file rather than the identity bundle — kick is moderation, not | ||
| # identity — and pulling it out first makes the surrounding identity | ||
| # block contiguous for the next extraction PR. | ||
| if [ -n "${_airc_lib_dir:-}" ] && [ -f "$_airc_lib_dir/airc_bash/cmd_kick.sh" ]; then | ||
| # shellcheck source=lib/airc_bash/cmd_kick.sh | ||
| source "$_airc_lib_dir/airc_bash/cmd_kick.sh" | ||
| else | ||
| echo "ERROR: airc_bash/cmd_kick.sh not found via lib-dir resolver." >&2 | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
cmd_identity.sh currently sources cmd_kick.sh as a side effect. This creates a hidden module dependency and breaks the pattern used elsewhere (the top-level airc script sources each extracted command file explicitly via the lib-dir resolver). Consider removing this nested source block and instead sourcing cmd_kick.sh directly from airc alongside the other cmd_*.sh modules.
| # cmd_kick extracted to lib/airc_bash/cmd_kick.sh | |
| # (#152 Phase 3 file split). Host-only peer eviction lives in its own | |
| # file rather than the identity bundle — kick is moderation, not | |
| # identity — and pulling it out first makes the surrounding identity | |
| # block contiguous for the next extraction PR. | |
| if [ -n "${_airc_lib_dir:-}" ] && [ -f "$_airc_lib_dir/airc_bash/cmd_kick.sh" ]; then | |
| # shellcheck source=lib/airc_bash/cmd_kick.sh | |
| source "$_airc_lib_dir/airc_bash/cmd_kick.sh" | |
| else | |
| echo "ERROR: airc_bash/cmd_kick.sh not found via lib-dir resolver." >&2 | |
| exit 1 | |
| fi | |
| # cmd_kick extracted to lib/airc_bash/cmd_kick.sh. | |
| # It must be sourced explicitly by the top-level `airc` loader alongside | |
| # the other cmd_*.sh modules, not as a side effect of loading identity. |
| # Identity bundle (cmd_away + cmd_identity + cmd_whois + _identity_* | ||
| # helpers) extracted to lib/airc_bash/cmd_identity.sh (#152 Phase 3 file | ||
| # split). The bundle was already cohesive — every helper is _identity_*, | ||
| # every public verb is about presence/persona — so it goes to ONE file. | ||
| if [ -n "${_airc_lib_dir:-}" ] && [ -f "$_airc_lib_dir/airc_bash/cmd_identity.sh" ]; then | ||
| # shellcheck source=lib/airc_bash/cmd_identity.sh | ||
| source "$_airc_lib_dir/airc_bash/cmd_identity.sh" | ||
| else | ||
| echo "ERROR: airc_bash/cmd_kick.sh not found via lib-dir resolver." >&2 | ||
| echo "ERROR: airc_bash/cmd_identity.sh not found via lib-dir resolver." >&2 |
There was a problem hiding this comment.
After extracting the identity bundle, airc now sources only cmd_identity.sh. Since cmd_kick.sh is its own extracted module (and airc does not source it elsewhere), the kick command is currently loaded only via a nested source inside cmd_identity.sh. To keep module boundaries consistent, consider sourcing cmd_kick.sh here in airc (near the other cmd_*.sh source blocks) and letting cmd_identity.sh contain only identity-related code.
Pulls the identity bundle (cmd_away + cmd_identity + cmd_whois + 7 identity* helpers, 422 lines) into lib/airc_bash/cmd_identity.sh. airc: 2711 → 2290 (-421). Stacks alongside merged #213-#218.