youmd 0.7.0 → 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.
- package/dist/commands/machine.d.ts +6 -0
- package/dist/commands/machine.d.ts.map +1 -0
- package/dist/commands/machine.js +142 -0
- package/dist/commands/machine.js.map +1 -0
- package/dist/commands/project-log.d.ts +13 -0
- package/dist/commands/project-log.d.ts.map +1 -0
- package/dist/commands/project-log.js +241 -0
- package/dist/commands/project-log.js.map +1 -0
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +12 -0
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +23 -0
- package/dist/commands/stack.js.map +1 -1
- package/dist/index.js +43 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/compiler.d.ts.map +1 -1
- package/dist/lib/compiler.js +10 -0
- package/dist/lib/compiler.js.map +1 -1
- package/package.json +1 -1
- package/scripts/env-vault/README.md +27 -10
- package/scripts/env-vault/backup.sh +46 -3
- package/scripts/env-vault/restore.sh +73 -7
- package/scripts/skillstack-sync/bootstrap-new-mac.sh +19 -5
- package/scripts/skillstack-sync/capture-agent-config.sh +109 -0
- package/scripts/skillstack-sync/context-sync.sh +344 -0
- package/scripts/skillstack-sync/restore-agent-config.sh +152 -0
- package/scripts/skillstack-sync/sync.sh +20 -6
|
@@ -1,8 +1,22 @@
|
|
|
1
|
-
# env-vault — Secure .env.local Backup & Restore
|
|
1
|
+
# env-vault — Secure .env.local + Agent-Auth Backup & Restore
|
|
2
2
|
|
|
3
|
-
Backs up all `.env.local` files across your CODE_2025 projects
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Backs up all `.env.local` files across your CODE_2025 projects **and** a fixed
|
|
4
|
+
set of hard agent-auth secret files into a single encrypted archive, and
|
|
5
|
+
restores them on a new Mac. No secret values ever appear in plaintext outside
|
|
6
|
+
the encrypted blob.
|
|
7
|
+
|
|
8
|
+
### What's in the vault
|
|
9
|
+
|
|
10
|
+
| Source path | Archive path | Restore destination |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `<CODE_2025>/<project>/.env.local` | `<project>/.env.local` | `<CODE_2025>/<project>/.env.local` |
|
|
13
|
+
| `~/.codex/auth.json` | `agent-auth/codex-auth.json` | `~/.codex/auth.json` |
|
|
14
|
+
| `~/.cursor/mcp.json` | `agent-auth/cursor-mcp.json` | `~/.cursor/mcp.json` |
|
|
15
|
+
| `~/.claude.json` | `agent-auth/claude.json` | `~/.claude.json` |
|
|
16
|
+
|
|
17
|
+
To add more agent-auth files, extend the `AGENT_SECRET_FILES` array near the
|
|
18
|
+
top of `backup.sh` and add the matching entry to `AGENT_AUTH_MAP` in
|
|
19
|
+
`restore.sh`.
|
|
6
20
|
|
|
7
21
|
---
|
|
8
22
|
|
|
@@ -21,7 +35,7 @@ bash cli/scripts/env-vault/backup.sh
|
|
|
21
35
|
|
|
22
36
|
This writes two files to `.env-vault/`:
|
|
23
37
|
- `env-vault-<date>.tar.<ext>` — encrypted archive (safe to transport)
|
|
24
|
-
- `manifest-<date>.txt` — variable names + counts only (safe to read, no values)
|
|
38
|
+
- `manifest-<date>.txt` — variable names + counts + agent-auth file paths/sizes only (safe to read, no values)
|
|
25
39
|
|
|
26
40
|
You will be prompted for a passphrase. Store it in **1Password** immediately.
|
|
27
41
|
|
|
@@ -40,7 +54,7 @@ Do NOT transfer via unencrypted email or public Slack.
|
|
|
40
54
|
# Install dependencies first (e.g. Node, pnpm, etc.), then:
|
|
41
55
|
youmd env restore /path/to/env-vault-<date>.tar.<ext>
|
|
42
56
|
|
|
43
|
-
# If
|
|
57
|
+
# If files already exist on the new Mac:
|
|
44
58
|
youmd env restore --force /path/to/env-vault-<date>.tar.<ext>
|
|
45
59
|
|
|
46
60
|
# or directly via bash:
|
|
@@ -48,8 +62,11 @@ bash cli/scripts/env-vault/restore.sh /path/to/env-vault-<date>.tar.<ext>
|
|
|
48
62
|
bash cli/scripts/env-vault/restore.sh --force /path/to/env-vault-<date>.tar.<ext>
|
|
49
63
|
```
|
|
50
64
|
|
|
51
|
-
The script
|
|
52
|
-
|
|
65
|
+
The script:
|
|
66
|
+
1. Creates `<CODE_2025>/<project>/.env.local` for each project.
|
|
67
|
+
2. Restores agent-auth files to their absolute home paths (`~/.codex/auth.json`, `~/.cursor/mcp.json`, `~/.claude.json`), creating parent directories as needed.
|
|
68
|
+
|
|
69
|
+
Existing files are backed up to `<path>.bak.<timestamp>` before overwrite (or silently overwritten with `--force`).
|
|
53
70
|
|
|
54
71
|
---
|
|
55
72
|
|
|
@@ -70,8 +87,8 @@ The encrypted file itself is safe to store anywhere. The passphrase is the secre
|
|
|
70
87
|
## Security Model
|
|
71
88
|
|
|
72
89
|
- **Encryption:** `age` (preferred) → `gpg AES-256` → `openssl AES-256-CBC PBKDF2`
|
|
73
|
-
- **What's in the encrypted archive:** full `.env.local` file contents
|
|
74
|
-
- **What's in plaintext:** only the project name + variable NAMES + count (the manifest)
|
|
90
|
+
- **What's in the encrypted archive:** full `.env.local` file contents + agent-auth files (`~/.codex/auth.json`, `~/.cursor/mcp.json`, `~/.claude.json`)
|
|
91
|
+
- **What's in plaintext:** only the project name + variable NAMES + count + agent-auth file paths/byte-sizes (the manifest)
|
|
75
92
|
- **Values:** never printed, echoed, logged, or written anywhere outside the encrypted blob
|
|
76
93
|
- **Passphrase:** stored nowhere by these scripts — you must store it in 1Password
|
|
77
94
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# env-vault/backup.sh — backs up all .env.local files under CODE_2025
|
|
3
|
-
#
|
|
4
|
-
# Only variable NAMES
|
|
2
|
+
# env-vault/backup.sh — backs up all .env.local files under CODE_2025 AND a
|
|
3
|
+
# fixed set of agent-auth secret files into an encrypted vault. NEVER prints,
|
|
4
|
+
# echoes, logs, or writes any secret VALUE. Only variable NAMES, counts, and
|
|
5
|
+
# file paths appear in plaintext output.
|
|
5
6
|
#
|
|
6
7
|
# Usage: bash backup.sh [--root <search-root>] [--out <output-dir>]
|
|
7
8
|
# Defaults:
|
|
@@ -14,6 +15,16 @@ set -euo pipefail
|
|
|
14
15
|
SEARCH_ROOT="${ENV_VAULT_ROOT:-/Users/houstongolden/Desktop/CODE_2025}"
|
|
15
16
|
OUTPUT_DIR="${ENV_VAULT_OUT:-/Users/houstongolden/Desktop/CODE_2025/youmd/.env-vault}"
|
|
16
17
|
|
|
18
|
+
# ── agent-auth secret files ────────────────────────────────────────────────────
|
|
19
|
+
# Absolute paths to hard agent-auth secrets that must travel with the vault.
|
|
20
|
+
# Each entry is archived as agent-auth/<stable-name> inside the tar.
|
|
21
|
+
# To add more: append to this array. Format: "absolute-path:stable-archive-name"
|
|
22
|
+
AGENT_SECRET_FILES=(
|
|
23
|
+
"${HOME}/.codex/auth.json:codex-auth.json"
|
|
24
|
+
"${HOME}/.cursor/mcp.json:cursor-mcp.json"
|
|
25
|
+
"${HOME}/.claude.json:claude.json"
|
|
26
|
+
)
|
|
27
|
+
|
|
17
28
|
# ── parse flags ────────────────────────────────────────────────────────────────
|
|
18
29
|
while [[ $# -gt 0 ]]; do
|
|
19
30
|
case $1 in
|
|
@@ -94,6 +105,38 @@ for ENV_FILE in "${ENV_FILES[@]}"; do
|
|
|
94
105
|
>> "${MANIFEST_PATH}"
|
|
95
106
|
done
|
|
96
107
|
|
|
108
|
+
# ── stage agent-auth secret files ─────────────────────────────────────────────
|
|
109
|
+
# Each entry in AGENT_SECRET_FILES has format "absolute-path:stable-archive-name".
|
|
110
|
+
# Files are stored under agent-auth/<stable-name> inside the archive.
|
|
111
|
+
# Only the path and byte-size appear in the manifest — never the contents.
|
|
112
|
+
AGENT_AUTH_STAGING="${STAGING_DIR}/agent-auth"
|
|
113
|
+
mkdir -p "${AGENT_AUTH_STAGING}"
|
|
114
|
+
AGENT_AUTH_COUNT=0
|
|
115
|
+
|
|
116
|
+
echo "" >> "${MANIFEST_PATH}"
|
|
117
|
+
echo "agent-auth files:" >> "${MANIFEST_PATH}"
|
|
118
|
+
|
|
119
|
+
for ENTRY in "${AGENT_SECRET_FILES[@]}"; do
|
|
120
|
+
SRC_PATH="${ENTRY%%:*}"
|
|
121
|
+
ARCHIVE_NAME="${ENTRY##*:}"
|
|
122
|
+
|
|
123
|
+
if [[ -f "${SRC_PATH}" ]]; then
|
|
124
|
+
cp "${SRC_PATH}" "${AGENT_AUTH_STAGING}/${ARCHIVE_NAME}"
|
|
125
|
+
FILE_BYTES=$(wc -c < "${SRC_PATH}" | tr -d ' ')
|
|
126
|
+
echo " agent-auth/${ARCHIVE_NAME} (${SRC_PATH}): ${FILE_BYTES} bytes" \
|
|
127
|
+
>> "${MANIFEST_PATH}"
|
|
128
|
+
echo " Staged agent-auth: ${SRC_PATH} → agent-auth/${ARCHIVE_NAME}"
|
|
129
|
+
(( AGENT_AUTH_COUNT++ )) || true
|
|
130
|
+
else
|
|
131
|
+
echo " agent-auth/${ARCHIVE_NAME} (${SRC_PATH}): NOT FOUND — skipped" \
|
|
132
|
+
>> "${MANIFEST_PATH}"
|
|
133
|
+
echo " Skipped (not found): ${SRC_PATH}"
|
|
134
|
+
fi
|
|
135
|
+
done
|
|
136
|
+
|
|
137
|
+
echo ""
|
|
138
|
+
echo "Staged ${AGENT_AUTH_COUNT} agent-auth file(s)."
|
|
139
|
+
|
|
97
140
|
echo "" >> "${MANIFEST_PATH}"
|
|
98
141
|
echo "SECURITY: The encrypted archive is safe to transport. Keep the passphrase private." \
|
|
99
142
|
>> "${MANIFEST_PATH}"
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# env-vault/restore.sh — restores .env.local files
|
|
3
|
-
# created by backup.sh. NEVER prints, echoes, or logs any
|
|
4
|
-
# Only prints which file paths were restored or skipped.
|
|
2
|
+
# env-vault/restore.sh — restores .env.local files AND agent-auth secrets from
|
|
3
|
+
# an encrypted vault created by backup.sh. NEVER prints, echoes, or logs any
|
|
4
|
+
# secret VALUES. Only prints which file paths were restored or skipped.
|
|
5
5
|
#
|
|
6
6
|
# Usage: bash restore.sh [--force] [--root <target-root>] <vault-file>
|
|
7
7
|
# vault-file: path to env-vault-*.tar.age / .tar.gpg / .tar.enc
|
|
8
|
-
# --force: overwrite existing
|
|
9
|
-
# --root: destination root
|
|
8
|
+
# --force: overwrite existing files without backing them up
|
|
9
|
+
# --root: destination root for .env.local files
|
|
10
|
+
# (default: /Users/houstongolden/Desktop/CODE_2025)
|
|
11
|
+
#
|
|
12
|
+
# agent-auth restore map (archive name → absolute home path):
|
|
13
|
+
# agent-auth/codex-auth.json → ~/.codex/auth.json
|
|
14
|
+
# agent-auth/cursor-mcp.json → ~/.cursor/mcp.json
|
|
15
|
+
# agent-auth/claude.json → ~/.claude.json
|
|
10
16
|
|
|
11
17
|
set -euo pipefail
|
|
12
18
|
|
|
19
|
+
# ── agent-auth restore map ─────────────────────────────────────────────────────
|
|
20
|
+
# Maps archive name (inside agent-auth/) to its absolute home destination.
|
|
21
|
+
# Format: "archive-name:absolute-destination-path"
|
|
22
|
+
# Must stay in sync with AGENT_SECRET_FILES in backup.sh.
|
|
23
|
+
AGENT_AUTH_MAP=(
|
|
24
|
+
"codex-auth.json:${HOME}/.codex/auth.json"
|
|
25
|
+
"cursor-mcp.json:${HOME}/.cursor/mcp.json"
|
|
26
|
+
"claude.json:${HOME}/.claude.json"
|
|
27
|
+
)
|
|
28
|
+
|
|
13
29
|
# ── defaults ──────────────────────────────────────────────────────────────────
|
|
14
30
|
TARGET_ROOT="${ENV_VAULT_RESTORE_ROOT:-/Users/houstongolden/Desktop/CODE_2025}"
|
|
15
31
|
FORCE=false
|
|
@@ -139,11 +155,61 @@ while IFS= read -r -d '' ENV_FILE; do
|
|
|
139
155
|
fi
|
|
140
156
|
done < <(find "${EXTRACT_DIR}" -name ".env.local" -print0)
|
|
141
157
|
|
|
158
|
+
# ── restore agent-auth files ───────────────────────────────────────────────────
|
|
159
|
+
AGENT_RESTORED=0
|
|
160
|
+
AGENT_SKIPPED=0
|
|
161
|
+
AGENT_BACKED_UP=0
|
|
162
|
+
|
|
163
|
+
AGENT_AUTH_SRC="${EXTRACT_DIR}/agent-auth"
|
|
164
|
+
|
|
165
|
+
if [[ -d "${AGENT_AUTH_SRC}" ]]; then
|
|
166
|
+
echo "Restoring agent-auth files…"
|
|
167
|
+
for ENTRY in "${AGENT_AUTH_MAP[@]}"; do
|
|
168
|
+
ARCHIVE_NAME="${ENTRY%%:*}"
|
|
169
|
+
DEST_PATH="${ENTRY##*:}"
|
|
170
|
+
SRC_FILE="${AGENT_AUTH_SRC}/${ARCHIVE_NAME}"
|
|
171
|
+
|
|
172
|
+
if [[ ! -f "${SRC_FILE}" ]]; then
|
|
173
|
+
echo " SKIPPED (not in vault): agent-auth/${ARCHIVE_NAME}"
|
|
174
|
+
(( AGENT_SKIPPED++ )) || true
|
|
175
|
+
continue
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
DEST_DIR="$(dirname "${DEST_PATH}")"
|
|
179
|
+
mkdir -p "${DEST_DIR}"
|
|
180
|
+
|
|
181
|
+
if [[ -f "${DEST_PATH}" ]]; then
|
|
182
|
+
if [[ "${FORCE}" == "true" ]]; then
|
|
183
|
+
cp "${SRC_FILE}" "${DEST_PATH}"
|
|
184
|
+
echo " RESTORED (overwrite): ${DEST_PATH}"
|
|
185
|
+
(( AGENT_RESTORED++ )) || true
|
|
186
|
+
else
|
|
187
|
+
TS="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
188
|
+
BAK="${DEST_PATH}.bak.${TS}"
|
|
189
|
+
cp "${DEST_PATH}" "${BAK}"
|
|
190
|
+
cp "${SRC_FILE}" "${DEST_PATH}"
|
|
191
|
+
echo " RESTORED (backed up old → $(basename "${BAK}")): ${DEST_PATH}"
|
|
192
|
+
(( AGENT_RESTORED++ )) || true
|
|
193
|
+
(( AGENT_BACKED_UP++ )) || true
|
|
194
|
+
fi
|
|
195
|
+
else
|
|
196
|
+
cp "${SRC_FILE}" "${DEST_PATH}"
|
|
197
|
+
echo " RESTORED (new): ${DEST_PATH}"
|
|
198
|
+
(( AGENT_RESTORED++ )) || true
|
|
199
|
+
fi
|
|
200
|
+
done
|
|
201
|
+
echo ""
|
|
202
|
+
else
|
|
203
|
+
echo "No agent-auth/ directory in vault — skipping agent-auth restore."
|
|
204
|
+
echo ""
|
|
205
|
+
fi
|
|
206
|
+
|
|
142
207
|
echo ""
|
|
143
208
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
144
209
|
echo " Restore summary"
|
|
145
210
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
146
|
-
echo " Restored: ${RESTORED} | Skipped: ${SKIPPED} | Old files backed up: ${BACKED_UP}"
|
|
211
|
+
echo " .env.local — Restored: ${RESTORED} | Skipped: ${SKIPPED} | Old files backed up: ${BACKED_UP}"
|
|
212
|
+
echo " agent-auth — Restored: ${AGENT_RESTORED} | Skipped: ${AGENT_SKIPPED} | Old files backed up: ${AGENT_BACKED_UP}"
|
|
147
213
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
148
214
|
echo ""
|
|
149
|
-
echo "Secrets are now in place. Do not print or share
|
|
215
|
+
echo "Secrets are now in place. Do not print or share secret files."
|
|
@@ -101,14 +101,29 @@ for skill in ${LOOSE_SKILLS}; do
|
|
|
101
101
|
done
|
|
102
102
|
|
|
103
103
|
# ---------------------------------------------------------------------------
|
|
104
|
-
step "5.
|
|
104
|
+
step "5. Restore agent config from agent-shared"
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
107
|
+
RESTORE_SCRIPT="${SCRIPT_DIR}/restore-agent-config.sh"
|
|
108
|
+
|
|
109
|
+
if [ -f "${RESTORE_SCRIPT}" ]; then
|
|
110
|
+
info "Running restore-agent-config.sh (backs up existing files, safe to re-run)..."
|
|
111
|
+
bash "${RESTORE_SCRIPT}"
|
|
112
|
+
info "Agent config restored."
|
|
113
|
+
else
|
|
114
|
+
warn "restore-agent-config.sh not found at ${RESTORE_SCRIPT} — skipping agent config restore."
|
|
115
|
+
warn "You can run it manually later once youmd is fully installed:"
|
|
116
|
+
warn " bash ${RESTORE_SCRIPT}"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
step "6. Reminder: restore secrets"
|
|
105
121
|
# ---------------------------------------------------------------------------
|
|
106
122
|
echo ""
|
|
107
123
|
echo " !! IMPORTANT: Secrets are NOT in git. Restore them separately:"
|
|
108
124
|
echo ""
|
|
109
|
-
echo " If you use the env-vault
|
|
125
|
+
echo " If you use the env-vault:"
|
|
110
126
|
echo " youmd env restore <vault-file> # CLI wrapper (preferred)"
|
|
111
|
-
echo " bash ~/Desktop/CODE_2025/youmd/cli/scripts/env-vault/restore.sh <vault-file>"
|
|
112
127
|
echo ""
|
|
113
128
|
echo " Secrets to restore (set in your shell profile or .env files):"
|
|
114
129
|
echo " OPENROUTER_API_KEY"
|
|
@@ -119,7 +134,7 @@ echo " ANTHROPIC_API_KEY"
|
|
|
119
134
|
echo ""
|
|
120
135
|
|
|
121
136
|
# ---------------------------------------------------------------------------
|
|
122
|
-
step "
|
|
137
|
+
step "7. Next steps"
|
|
123
138
|
# ---------------------------------------------------------------------------
|
|
124
139
|
echo ""
|
|
125
140
|
echo " Bootstrap complete. To activate the auto-sync daemons, run:"
|
|
@@ -127,7 +142,6 @@ echo ""
|
|
|
127
142
|
echo " youmd stack daemon install # preferred (CLI-native)"
|
|
128
143
|
echo ""
|
|
129
144
|
echo " Or run the raw script directly:"
|
|
130
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
131
145
|
echo " bash ${SCRIPT_DIR}/install-daemons.sh"
|
|
132
146
|
echo ""
|
|
133
147
|
echo " To do a manual sync now:"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# capture-agent-config.sh — snapshot NON-SECRET agent config into ~/.agent-shared/
|
|
3
|
+
#
|
|
4
|
+
# This captures the agent-behavior config that isn't already in a synced repo —
|
|
5
|
+
# Claude/Codex/Warp settings, slash commands, plugin list, the orphaned
|
|
6
|
+
# ~/.agents skills, and the launchd/cron automations — into the agent-shared
|
|
7
|
+
# repo so they travel across machines. The skillstack-sync daemon then commits +
|
|
8
|
+
# pushes agent-shared, and `youmd machine setup`/restore applies them on a new Mac.
|
|
9
|
+
#
|
|
10
|
+
# SECRETS NEVER GO HERE. agent-shared is a git repo. Live secrets (codex
|
|
11
|
+
# auth.json, cursor mcp.json, ~/.claude.json BAMF token, .env.local) travel via
|
|
12
|
+
# the ENCRYPTED env-vault instead. This script captures only files confirmed to
|
|
13
|
+
# be secret-free, and a final guard greps the staged output for secret patterns
|
|
14
|
+
# and ABORTS if any are found (nothing is left in agent-shared on abort).
|
|
15
|
+
#
|
|
16
|
+
# bash 3.2 / BSD safe. Idempotent. --dry-run to preview.
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
AGENT_SHARED="${HOME}/.agent-shared"
|
|
21
|
+
DEST="${AGENT_SHARED}/agent-config"
|
|
22
|
+
LOG_DIR="${HOME}/.youmd/logs"
|
|
23
|
+
LOG_FILE="${LOG_DIR}/capture-agent-config.log"
|
|
24
|
+
|
|
25
|
+
DRY_RUN=0
|
|
26
|
+
for arg in "$@"; do
|
|
27
|
+
case "$arg" in
|
|
28
|
+
--dry-run) DRY_RUN=1 ;;
|
|
29
|
+
*) echo "Unknown flag: $arg" >&2; exit 1 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
mkdir -p "${LOG_DIR}"
|
|
34
|
+
log() { local ts; ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"; echo "[${ts}] $*"; echo "[${ts}] $*" >> "${LOG_FILE}"; }
|
|
35
|
+
is_dry() { [ "${DRY_RUN}" -eq 1 ]; }
|
|
36
|
+
|
|
37
|
+
if [ ! -d "${AGENT_SHARED}/.git" ]; then
|
|
38
|
+
log "ERROR: ${AGENT_SHARED} is not a git repo — run machine setup first."
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# copy_in <src> <dest-subpath> — copy a file/dir into the staging dest if it exists
|
|
43
|
+
copy_in() {
|
|
44
|
+
local src="$1" rel="$2" target
|
|
45
|
+
target="${DEST}/${rel}"
|
|
46
|
+
if [ ! -e "${src}" ]; then return 0; fi
|
|
47
|
+
if is_dry; then log "DRY would capture ${src} → agent-config/${rel}"; return 0; fi
|
|
48
|
+
mkdir -p "$(dirname "${target}")"
|
|
49
|
+
if [ -d "${src}" ]; then
|
|
50
|
+
rsync -a --delete "${src}/" "${target}/"
|
|
51
|
+
else
|
|
52
|
+
cp "${src}" "${target}"
|
|
53
|
+
fi
|
|
54
|
+
log "captured ${src} → agent-config/${rel}"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
log "=== capture-agent-config START ($([ "${DRY_RUN}" -eq 1 ] && echo DRY || echo LIVE)) ==="
|
|
58
|
+
|
|
59
|
+
# ── Claude config (settings have no raw secrets; ~/.claude.json is EXCLUDED — vaulted) ──
|
|
60
|
+
copy_in "${HOME}/.claude/settings.json" "claude/settings.json"
|
|
61
|
+
copy_in "${HOME}/.claude/settings.local.json" "claude/settings.local.json"
|
|
62
|
+
copy_in "${HOME}/.claude/commands" "claude/commands"
|
|
63
|
+
copy_in "${HOME}/.claude/mcp.json" "claude/mcp.json"
|
|
64
|
+
copy_in "${HOME}/.claude/plugins/installed_plugins.json" "claude/plugins/installed_plugins.json"
|
|
65
|
+
|
|
66
|
+
# ── Codex config (config.toml only; auth.json is EXCLUDED — vaulted) ──
|
|
67
|
+
copy_in "${HOME}/.codex/config.toml" "codex/config.toml"
|
|
68
|
+
|
|
69
|
+
# ── Warp (no secrets) ──
|
|
70
|
+
copy_in "${HOME}/.warp/settings.toml" "warp/settings.toml"
|
|
71
|
+
copy_in "${HOME}/.warp/keybindings.yaml" "warp/keybindings.yaml"
|
|
72
|
+
|
|
73
|
+
# ── Orphaned ~/.agents skills (no repo of their own today) ──
|
|
74
|
+
copy_in "${HOME}/.agents/skills/find-skills" "agents-skills/find-skills"
|
|
75
|
+
copy_in "${HOME}/.agents/skills/ui-ux-pro-max" "agents-skills/ui-ux-pro-max"
|
|
76
|
+
|
|
77
|
+
# ── Automations: launchd plists (HOME-templated) + crontab snapshot ──
|
|
78
|
+
capture_plist() {
|
|
79
|
+
local label="$1" src="${HOME}/Library/LaunchAgents/$1.plist" target="${DEST}/automations/launchd/$1.plist"
|
|
80
|
+
if [ ! -f "${src}" ]; then return 0; fi
|
|
81
|
+
if is_dry; then log "DRY would capture plist ${label} (HOME-templated)"; return 0; fi
|
|
82
|
+
mkdir -p "$(dirname "${target}")"
|
|
83
|
+
sed "s|${HOME}|__HOME__|g" "${src}" > "${target}"
|
|
84
|
+
log "captured plist ${label} → agent-config/automations/launchd/${label}.plist"
|
|
85
|
+
}
|
|
86
|
+
capture_plist "com.youmd.skillstack-sync"
|
|
87
|
+
capture_plist "com.youmd.identity-sync"
|
|
88
|
+
capture_plist "com.houstongolden.agent-runtime-guard"
|
|
89
|
+
|
|
90
|
+
if ! is_dry; then
|
|
91
|
+
mkdir -p "${DEST}/automations"
|
|
92
|
+
crontab -l 2>/dev/null > "${DEST}/automations/crontab.txt" || true
|
|
93
|
+
log "captured crontab → agent-config/automations/crontab.txt"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ── SECRET-LEAK GUARD — abort if anything captured looks like a live secret ──
|
|
97
|
+
if ! is_dry && [ -d "${DEST}" ]; then
|
|
98
|
+
# Match real secret token shapes; allow bare key NAMES (KEY=) which are fine.
|
|
99
|
+
HITS="$(grep -rIlE 'sk-ant-[A-Za-z0-9_-]{20}|sk-[A-Za-z0-9]{32}|ghp_[A-Za-z0-9]{30}|gho_[A-Za-z0-9]{30}|Bearer [A-Za-z0-9._-]{20}|AKIA[0-9A-Z]{16}|xox[baprs]-[A-Za-z0-9-]{10}' "${DEST}" 2>/dev/null || true)"
|
|
100
|
+
if [ -n "${HITS}" ]; then
|
|
101
|
+
log "ABORT: possible secret(s) found in captured config — removing capture, nothing committed:"
|
|
102
|
+
log "${HITS}"
|
|
103
|
+
rm -rf "${DEST}"
|
|
104
|
+
exit 1
|
|
105
|
+
fi
|
|
106
|
+
log "secret-leak guard: clean (no live secret patterns in captured config)"
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
log "=== capture-agent-config DONE ==="
|