Compare commits
2
Commits
f4fca1797f
...
ffad7e56ea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffad7e56ea | ||
|
|
34bc1663ed |
No files matched your search
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
# The Mac mini's shell. macOS stays on zsh: its bash is 3.2, and
|
||||||
|
# config/bash/shell leans on Linux-only tools (stat -c, ksshaskpass, the nvm
|
||||||
|
# profile script), so this is a small zsh counterpart rather than a port.
|
||||||
|
# Linked to ~/.zshrc. Homebrew's PATH comes from ~/.zprofile (brew shellenv).
|
||||||
|
export PANAMA_PATH="$HOME/.local/share/Panama"
|
||||||
|
|
||||||
|
export EDITOR="nvim"
|
||||||
|
export SUDO_EDITOR="$EDITOR"
|
||||||
|
|
||||||
|
export BUN_INSTALL="$HOME/.bun"
|
||||||
|
export PATH="$HOME/.local/bin:$BUN_INSTALL/bin:$PANAMA_PATH/bin:$PATH"
|
||||||
|
|
||||||
|
# History shared across sessions, so tmux panes see each other's commands.
|
||||||
|
HISTFILE="$HOME/.zsh_history"
|
||||||
|
HISTSIZE=50000
|
||||||
|
SAVEHIST=50000
|
||||||
|
setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE
|
||||||
|
|
||||||
|
# Emacs keys, like bash's readline: ctrl-a/e/r work as they do on Linux.
|
||||||
|
bindkey -e
|
||||||
|
|
||||||
|
autoload -Uz compinit && compinit
|
||||||
|
[ -s "$BUN_INSTALL/_bun" ] && source "$BUN_INSTALL/_bun"
|
||||||
|
|
||||||
|
# Same SSH behaviour as config/bash/shell: an SSH login lands in a tmux
|
||||||
|
# session that survives a dropped connection. PANAMA_SSH_TMUX=off opts out.
|
||||||
|
if [[ -n "$SSH_CONNECTION" && -z "$TMUX" && -o interactive &&
|
||||||
|
"${PANAMA_SSH_TMUX:-on}" != "off" ]] && command -v tmux >/dev/null 2>&1; then
|
||||||
|
exec tmux new-session -A -s main
|
||||||
|
fi
|
||||||
|
|
||||||
|
alias c="clear"
|
||||||
|
alias n="nvim"
|
||||||
|
alias n.="nvim ."
|
||||||
|
alias ..="cd .."
|
||||||
|
alias ...="cd ../.."
|
||||||
|
alias ....="cd ../../.."
|
||||||
|
alias letscode="ranger ~/Documents/Documents/Code"
|
||||||
|
alias commit-repo='git add -A && git commit -m "Update stuff" && git push'
|
||||||
|
alias ls='eza -lh --group-directories-first --icons=auto'
|
||||||
|
alias lsa='ls -a'
|
||||||
|
alias lt='eza --tree --level=2 --long --icons=auto --git'
|
||||||
|
alias ff="fzf --preview 'bat --style=numbers --color=always {}'"
|
||||||
|
compress() { tar -czf "${1%/}.tar.gz" "${1%/}"; }
|
||||||
|
alias decompress="tar -xzf"
|
||||||
|
|
||||||
|
# Xcode cannot sign from an SSH session while the login keychain is locked
|
||||||
|
# (errSecInternalComponent). Run this once per session before a build.
|
||||||
|
alias unlock-keychain='security unlock-keychain ~/Library/Keychains/login.keychain-db'
|
||||||
|
|
||||||
|
eval "$(zoxide init zsh)"
|
||||||
|
source <(fzf --zsh)
|
||||||
|
eval "$(oh-my-posh init zsh --config "$PANAMA_PATH/config/dot/ohmyposh/gib.omp.json")"
|
||||||
+62
-7
@@ -18,9 +18,15 @@
|
|||||||
# This is personal content, so it obeys the same interview decision link-user
|
# This is personal content, so it obeys the same interview decision link-user
|
||||||
# does. A machine that never said yes registers nothing.
|
# does. A machine that never said yes registers nothing.
|
||||||
#
|
#
|
||||||
# Only Claude Code is handled. Codex stores its servers inside config.toml, and
|
# Claude Code and opencode are handled. Codex stores its servers inside
|
||||||
# rewriting a section of somebody's live TOML is a worse failure mode than
|
# config.toml, and rewriting a section of somebody's live TOML is a worse
|
||||||
# leaving two lines for them to paste once.
|
# failure mode than leaving two lines for them to paste once.
|
||||||
|
#
|
||||||
|
# opencode has no CLI for this either, but its config is plain JSON, so this
|
||||||
|
# stage merges two keys into it with jq: one mcp entry per server row, and the
|
||||||
|
# rules directory under instructions, because opencode reads ~/.claude/CLAUDE.md
|
||||||
|
# and ~/.claude/skills on its own but not ~/.claude/rules. Every other key in
|
||||||
|
# that file is left as it was.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -44,8 +50,12 @@ if [[ "$decision" != "yes" ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v claude >/dev/null 2>&1; then
|
has_claude=false
|
||||||
log "Claude Code is not installed; nothing to register."
|
has_opencode=false
|
||||||
|
command -v claude >/dev/null 2>&1 && has_claude=true
|
||||||
|
command -v opencode >/dev/null 2>&1 && has_opencode=true
|
||||||
|
if ! $has_claude && ! $has_opencode; then
|
||||||
|
log "Neither Claude Code nor opencode is installed; nothing to register."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -62,6 +72,8 @@ fi
|
|||||||
|
|
||||||
registered=0
|
registered=0
|
||||||
skipped=0
|
skipped=0
|
||||||
|
# The opencode mcp object, built up one server at a time.
|
||||||
|
opencode_mcp='{}'
|
||||||
|
|
||||||
while read -r name transport target token_var _rest; do
|
while read -r name transport target token_var _rest; do
|
||||||
case "${name:-}" in ''|'#'*) continue ;; esac
|
case "${name:-}" in ''|'#'*) continue ;; esac
|
||||||
@@ -103,6 +115,20 @@ while read -r name transport target token_var _rest; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
auth=""
|
||||||
|
[[ "${args[0]:-}" == -H ]] && auth="${args[1]#Authorization: }"
|
||||||
|
|
||||||
|
if [[ "$transport" == stdio ]]; then
|
||||||
|
entry="$(jq -cn --arg c "$launcher" --arg t "$token" \
|
||||||
|
'{type: "local", command: [$c]} + (if $t == "" then {} else {environment: {MCP_TOKEN: $t}} end)')"
|
||||||
|
else
|
||||||
|
entry="$(jq -cn --arg u "$url" --arg a "$auth" \
|
||||||
|
'{type: "remote", url: $u} + (if $a == "" then {} else {headers: {Authorization: $a}} end)')"
|
||||||
|
fi
|
||||||
|
opencode_mcp="$(jq -c --arg n "$name" --argjson e "$entry" '.[$n] = $e' <<<"$opencode_mcp")"
|
||||||
|
|
||||||
|
$has_claude || continue
|
||||||
|
|
||||||
# A server already registered exactly as this row would register it is left
|
# A server already registered exactly as this row would register it is left
|
||||||
# alone. Removing and re-adding it would throw away the OAuth session of a
|
# alone. Removing and re-adding it would throw away the OAuth session of a
|
||||||
# server that signs in on its own (bill-tracker, atlassian), so every
|
# server that signs in on its own (bill-tracker, atlassian), so every
|
||||||
@@ -114,8 +140,6 @@ while read -r name transport target token_var _rest; do
|
|||||||
'.mcpServers[$n] // {} | {command, env: (if (.env // {}) == {} then null else .env end)}' \
|
'.mcpServers[$n] // {} | {command, env: (if (.env // {}) == {} then null else .env end)}' \
|
||||||
"$HOME/.claude.json" 2>/dev/null || true)"
|
"$HOME/.claude.json" 2>/dev/null || true)"
|
||||||
else
|
else
|
||||||
auth=""
|
|
||||||
[[ "${args[0]:-}" == -H ]] && auth="${args[1]#Authorization: }"
|
|
||||||
want="$(jq -cn --arg u "$url" --arg a "$auth" \
|
want="$(jq -cn --arg u "$url" --arg a "$auth" \
|
||||||
'{url: $u, auth: (if $a == "" then null else $a end)}')"
|
'{url: $u, auth: (if $a == "" then null else $a end)}')"
|
||||||
have="$(jq -c --arg n "$name" \
|
have="$(jq -c --arg n "$name" \
|
||||||
@@ -146,5 +170,36 @@ while read -r name transport target token_var _rest; do
|
|||||||
fi
|
fi
|
||||||
done <"$SERVERS"
|
done <"$SERVERS"
|
||||||
|
|
||||||
|
if $has_claude; then
|
||||||
log "MCP servers: $registered registered, $skipped skipped."
|
log "MCP servers: $registered registered, $skipped skipped."
|
||||||
log "Claude Code loads them at start, so restart a running session to pick them up."
|
log "Claude Code loads them at start, so restart a running session to pick them up."
|
||||||
|
fi
|
||||||
|
|
||||||
|
$has_opencode || exit 0
|
||||||
|
|
||||||
|
# opencode reads opencode.jsonc or opencode.json, whichever this machine has.
|
||||||
|
# The file holds tokens once this runs, so it is written private and swapped in
|
||||||
|
# whole, the way ~/.claude.json already holds them for Claude Code.
|
||||||
|
OPENCODE_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/opencode"
|
||||||
|
opencode_config="$OPENCODE_DIR/opencode.jsonc"
|
||||||
|
[[ -e "$opencode_config" ]] || opencode_config="$OPENCODE_DIR/opencode.json"
|
||||||
|
rules="$HOME/.claude/rules/*.md"
|
||||||
|
|
||||||
|
mkdir -p "$OPENCODE_DIR"
|
||||||
|
current='{"$schema": "https://opencode.ai/config.json"}'
|
||||||
|
[[ -e "$opencode_config" ]] && current="$(cat "$opencode_config")"
|
||||||
|
|
||||||
|
# jq cannot read JSONC comments. A file that has them is left alone rather
|
||||||
|
# than rewritten without them.
|
||||||
|
if ! merged="$(jq --argjson mcp "$opencode_mcp" --arg rules "$rules" \
|
||||||
|
'.mcp = ((.mcp // {}) + $mcp) | .instructions = (((.instructions // []) - [$rules]) + [$rules])' \
|
||||||
|
<<<"$current" 2>/dev/null)"; then
|
||||||
|
warn "Could not parse $opencode_config as JSON; opencode MCP servers not written."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmp="$(mktemp "$OPENCODE_DIR/.opencode-config.XXXXXX")"
|
||||||
|
chmod 600 "$tmp"
|
||||||
|
printf '%s\n' "$merged" >"$tmp"
|
||||||
|
mv "$tmp" "$opencode_config"
|
||||||
|
log "opencode: $(jq -r 'length' <<<"$opencode_mcp") MCP servers and the rules written to $opencode_config."
|
||||||
+3
-3
@@ -12,9 +12,9 @@ and one file says where each piece goes.
|
|||||||
|
|
||||||
| Path | Goes to | Why |
|
| Path | Goes to | Why |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `agents/AGENTS.md` | `~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md` | Two tools, two names, one file. These were byte-identical copies before this, waiting to disagree. |
|
| `agents/AGENTS.md` | `~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, `~/.config/opencode/AGENTS.md` | Three tools, one file. These were byte-identical copies before this, waiting to disagree. |
|
||||||
| `agents/skills/` | `~/.agents/skills`, `~/.claude/skills` | Personal skills live once in the checkout. Both destinations use `linkdir` so Panama's shipped skills can live beside them. |
|
| `agents/skills/` | `~/.agents/skills`, `~/.claude/skills` | Personal skills live once in the checkout. Both destinations use `linkdir` so Panama's shipped skills can live beside them. opencode reads both directories itself. |
|
||||||
| `agents/rules/` | `~/.claude/rules` | |
|
| `agents/rules/` | `~/.claude/rules` | opencode loads these through `instructions` in its config, which `setup/scripts/link-mcp` writes. |
|
||||||
| `ssh/config` | `~/.ssh/config` | Host aliases only. Keys are per-machine and are never tracked. |
|
| `ssh/config` | `~/.ssh/config` | Host aliases only. Keys are per-machine and are never tracked. |
|
||||||
| `espanso/identity.yml` | `~/.config/espanso/match/identity.yml` | Copied, not linked, because a machine may add its own triggers. |
|
| `espanso/identity.yml` | `~/.config/espanso/match/identity.yml` | Copied, not linked, because a machine may add its own triggers. |
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -23,10 +23,11 @@
|
|||||||
# Gabriel's agent instructions on their machine.
|
# Gabriel's agent instructions on their machine.
|
||||||
|
|
||||||
# ── Agents ───────────────────────────────────────────────────────────────────
|
# ── Agents ───────────────────────────────────────────────────────────────────
|
||||||
# One file, two names. Claude Code reads CLAUDE.md and Codex reads AGENTS.md,
|
# One file, three names. Claude Code reads CLAUDE.md, Codex and opencode read
|
||||||
# and before this they were two byte-identical copies waiting to disagree.
|
# AGENTS.md, and before this they were byte-identical copies waiting to disagree.
|
||||||
link agents/AGENTS.md ~/.claude/CLAUDE.md
|
link agents/AGENTS.md ~/.claude/CLAUDE.md
|
||||||
link agents/AGENTS.md ~/.codex/AGENTS.md
|
link agents/AGENTS.md ~/.codex/AGENTS.md
|
||||||
|
link agents/AGENTS.md ~/.config/opencode/AGENTS.md
|
||||||
|
|
||||||
# Skills, at both paths that look for them. Each tracked skill is linked from
|
# Skills, at both paths that look for them. Each tracked skill is linked from
|
||||||
# this checkout so edits stay shared and `panama update` offers to commit them.
|
# this checkout so edits stay shared and `panama update` offers to commit them.
|
||||||
|
|||||||
Reference in new issue
Block a user