youmd 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env bash
2
+ # restore-agent-config.sh — apply ~/.agent-shared/agent-config/ back onto this machine
3
+ #
4
+ # Mirror-image of capture-agent-config.sh. Takes each item in agent-config/
5
+ # and copies it to its canonical home location, backing up any existing
6
+ # file/dir to <dest>.bak.<UTC-ts> first (unless --force skips the backup).
7
+ #
8
+ # Restored mappings:
9
+ # agent-config/claude/* → ~/.claude/
10
+ # agent-config/codex/config.toml → ~/.codex/config.toml
11
+ # agent-config/warp/* → ~/.warp/
12
+ # agent-config/agents-skills/* → ~/.agents/skills/
13
+ # agent-config/automations/launchd/*.plist → ~/Library/LaunchAgents/ (HOME templated back)
14
+ # agent-config/automations/crontab.txt → PRINTED ONLY (user must merge manually)
15
+ #
16
+ # bash 3.2 / BSD safe. Idempotent. --dry-run to preview without writing.
17
+ # --force to skip per-file backups (still idempotent, overwrites in place).
18
+ #
19
+ # SECRETS: there should be none in agent-config (the capture script guards
20
+ # against it), but this script never prints file contents — only paths.
21
+ #
22
+ # Usage: bash restore-agent-config.sh [--dry-run] [--force]
23
+
24
+ set -euo pipefail
25
+
26
+ AGENT_SHARED="${HOME}/.agent-shared"
27
+ SRC="${AGENT_SHARED}/agent-config"
28
+ LOG_DIR="${HOME}/.youmd/logs"
29
+ LOG_FILE="${LOG_DIR}/restore-agent-config.log"
30
+
31
+ DRY_RUN=0
32
+ FORCE=0
33
+ for arg in "$@"; do
34
+ case "$arg" in
35
+ --dry-run) DRY_RUN=1 ;;
36
+ --force) FORCE=1 ;;
37
+ *) echo "Unknown flag: $arg" >&2; exit 1 ;;
38
+ esac
39
+ done
40
+
41
+ mkdir -p "${LOG_DIR}"
42
+ log() { local ts; ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"; echo "[${ts}] $*"; echo "[${ts}] $*" >> "${LOG_FILE}"; }
43
+ is_dry() { [ "${DRY_RUN}" -eq 1 ]; }
44
+ is_force() { [ "${FORCE}" -eq 1 ]; }
45
+
46
+ if [ ! -d "${AGENT_SHARED}/.git" ]; then
47
+ log "ERROR: ${AGENT_SHARED} is not a git repo — run 'youmd machine setup' first."
48
+ exit 1
49
+ fi
50
+
51
+ if [ ! -d "${SRC}" ]; then
52
+ log "ERROR: ${SRC} does not exist — nothing to restore. Run 'youmd machine capture' on the source machine first."
53
+ exit 1
54
+ fi
55
+
56
+ log "=== restore-agent-config START ($([ "${DRY_RUN}" -eq 1 ] && echo DRY || echo LIVE) $([ "${FORCE}" -eq 1 ] && echo FORCE || echo SAFE)) ==="
57
+
58
+ # backup_dest <path>
59
+ # If the dest exists and --force is not set, back it up.
60
+ backup_dest() {
61
+ local dest="$1"
62
+ if [ -e "${dest}" ] && ! is_force; then
63
+ local ts; ts="$(date -u +"%Y%m%dT%H%M%SZ")"
64
+ local bak="${dest}.bak.${ts}"
65
+ if is_dry; then
66
+ log "DRY would backup ${dest} → ${bak}"
67
+ else
68
+ mv "${dest}" "${bak}"
69
+ log "backed up ${dest} → ${bak}"
70
+ fi
71
+ fi
72
+ }
73
+
74
+ # copy_out <src-relative-to-agent-config> <absolute-dest>
75
+ # Copy a file or directory from agent-config onto this machine.
76
+ copy_out() {
77
+ local rel="$1" dest="$2" src
78
+ src="${SRC}/${rel}"
79
+ if [ ! -e "${src}" ]; then return 0; fi
80
+
81
+ if is_dry; then
82
+ log "DRY would restore agent-config/${rel} → ${dest}"
83
+ return 0
84
+ fi
85
+
86
+ mkdir -p "$(dirname "${dest}")"
87
+ backup_dest "${dest}"
88
+ if [ -d "${src}" ]; then
89
+ rsync -a "${src}/" "${dest}/"
90
+ else
91
+ cp "${src}" "${dest}"
92
+ fi
93
+ log "restored agent-config/${rel} → ${dest}"
94
+ }
95
+
96
+ # ── Claude config ──────────────────────────────────────────────────────────────
97
+ copy_out "claude/settings.json" "${HOME}/.claude/settings.json"
98
+ copy_out "claude/settings.local.json" "${HOME}/.claude/settings.local.json"
99
+ copy_out "claude/commands" "${HOME}/.claude/commands"
100
+ copy_out "claude/mcp.json" "${HOME}/.claude/mcp.json"
101
+ copy_out "claude/plugins/installed_plugins.json" "${HOME}/.claude/plugins/installed_plugins.json"
102
+
103
+ # ── Codex config ───────────────────────────────────────────────────────────────
104
+ copy_out "codex/config.toml" "${HOME}/.codex/config.toml"
105
+
106
+ # ── Warp ───────────────────────────────────────────────────────────────────────
107
+ copy_out "warp/settings.toml" "${HOME}/.warp/settings.toml"
108
+ copy_out "warp/keybindings.yaml" "${HOME}/.warp/keybindings.yaml"
109
+
110
+ # ── Orphaned ~/.agents skills ──────────────────────────────────────────────────
111
+ copy_out "agents-skills/find-skills" "${HOME}/.agents/skills/find-skills"
112
+ copy_out "agents-skills/ui-ux-pro-max" "${HOME}/.agents/skills/ui-ux-pro-max"
113
+
114
+ # ── Automations: launchd plists (HOME-templated → real HOME) ───────────────────
115
+ LAUNCH_AGENTS_DIR="${HOME}/Library/LaunchAgents"
116
+ LAUNCHD_SRC="${SRC}/automations/launchd"
117
+ if [ -d "${LAUNCHD_SRC}" ]; then
118
+ # BSD-compatible glob: use find to enumerate plists
119
+ while IFS= read -r plist_src; do
120
+ name="$(basename "${plist_src}")"
121
+ dest="${LAUNCH_AGENTS_DIR}/${name}"
122
+ if is_dry; then
123
+ log "DRY would restore plist ${name} → ${dest} (with __HOME__ → \$HOME)"
124
+ else
125
+ mkdir -p "${LAUNCH_AGENTS_DIR}"
126
+ backup_dest "${dest}"
127
+ # Replace __HOME__ placeholder with the real HOME value (BSD sed, no -i extension trick)
128
+ sed "s|__HOME__|${HOME}|g" "${plist_src}" > "${dest}"
129
+ log "restored plist ${name} → ${dest}"
130
+ fi
131
+ log "NOTE: to load this daemon run: launchctl load -w ${dest}"
132
+ log " (or run: youmd stack daemon install — covers the youmd ones)"
133
+ done < <(find "${LAUNCHD_SRC}" -maxdepth 1 -name "*.plist" 2>/dev/null || true)
134
+ fi
135
+
136
+ # ── Crontab — PRINT ONLY, never overwrite automatically ────────────────────────
137
+ CRONTAB_SRC="${SRC}/automations/crontab.txt"
138
+ if [ -f "${CRONTAB_SRC}" ]; then
139
+ log "crontab.txt found — NOT writing automatically (clobbering crontab is destructive)."
140
+ log "Inspect and merge manually with: crontab -e"
141
+ echo ""
142
+ echo " ── captured crontab entries (merge manually with 'crontab -e') ──"
143
+ # Print each line with a leading " " indent so it's visually distinct.
144
+ # Use a while-read loop (no cat) to stay shell-safe.
145
+ while IFS= read -r line; do
146
+ echo " ${line}"
147
+ done < "${CRONTAB_SRC}"
148
+ echo " ── end crontab ──"
149
+ echo ""
150
+ fi
151
+
152
+ log "=== restore-agent-config DONE ==="
@@ -30,12 +30,15 @@ SCISTACK="${HOME}/.claude/scistack"
30
30
  LOOSE_SKILLS="agent-runtime-guard agent-stack-sync continue skill-governor"
31
31
 
32
32
  # Repos to sync (space-separated absolute paths; override via env).
33
- # v1 default is agent-shared ONLY — it's purpose-built for sync and safe to
34
- # auto-commit. scistack is intentionally NOT auto-synced by default: it holds
35
- # protected learning-loop IP where auto-committing WIP on a timer is undesirable.
36
- # To opt scistack (or other repos) in, set:
37
- # SKILLSTACK_REPOS="$HOME/.agent-shared $HOME/.claude/scistack"
38
- DEFAULT_REPOS="${AGENT_SHARED}"
33
+ # Houston's agent skill/stack layer syncs by DEFAULT:
34
+ # - ~/.agent-shared → shared agent config + loose skills (houstongolden/agent-shared)
35
+ # - ~/.claude/scistack ALL science skills (Hubify-Projects/scistack): 68 skill
36
+ # symlink targets under hubstack/ + astrostack/ + extensions/, incl. the
37
+ # learning-loop IP. Conflict-safe (commit→merge-pull→push, abort on conflict),
38
+ # so auto-syncing his own repo is exactly the cross-machine behavior intended.
39
+ # gstack is NOT here (upstream garrytan/gstack, reinstalled via gstack-upgrade).
40
+ # Add more repos by setting SKILLSTACK_REPOS to a space-separated path list.
41
+ DEFAULT_REPOS="${AGENT_SHARED} ${SCISTACK}"
39
42
  SKILLSTACK_REPOS="${SKILLSTACK_REPOS:-${DEFAULT_REPOS}}"
40
43
 
41
44
  DRY_RUN=0
@@ -291,6 +294,17 @@ main() {
291
294
  log "skillstack-sync START [${mode}] on $(hostname_short)"
292
295
  log "============================================================"
293
296
 
297
+ # Step 0: Capture non-secret agent config (claude/codex/warp settings, slash
298
+ # commands, plugin list, orphan skills, automations) into agent-shared so it
299
+ # travels with the sync. Secret-leak-guarded; never blocks the sync on failure.
300
+ if [ -x "${SCRIPT_DIR}/capture-agent-config.sh" ]; then
301
+ if is_dry; then
302
+ bash "${SCRIPT_DIR}/capture-agent-config.sh" --dry-run || log_warn "capture-agent-config dry-run failed (non-fatal)"
303
+ else
304
+ bash "${SCRIPT_DIR}/capture-agent-config.sh" || log_warn "capture-agent-config failed (non-fatal — continuing sync)"
305
+ fi
306
+ fi
307
+
294
308
  # Step 1: Mirror loose skills into agent-shared BEFORE syncing it
295
309
  mirror_loose_skills_to_repo
296
310