youmd 0.8.0 → 0.8.5
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/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +20 -2
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/env.d.ts +21 -4
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +250 -24
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +20 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/machine.d.ts +28 -1
- package/dist/commands/machine.d.ts.map +1 -1
- package/dist/commands/machine.js +529 -4
- package/dist/commands/machine.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +862 -17
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/prompts.d.ts +19 -0
- package/dist/commands/prompts.d.ts.map +1 -1
- package/dist/commands/prompts.js +304 -1
- package/dist/commands/prompts.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +28 -8
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts +3 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +26 -12
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +19 -15
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +20 -17
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +38 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +235 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.js +157 -31
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +398 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +104 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/daemon.d.ts +26 -0
- package/dist/lib/daemon.d.ts.map +1 -0
- package/dist/lib/daemon.js +187 -0
- package/dist/lib/daemon.js.map +1 -0
- package/dist/lib/first-run.d.ts +1 -1
- package/dist/lib/first-run.d.ts.map +1 -1
- package/dist/lib/first-run.js +8 -0
- package/dist/lib/first-run.js.map +1 -1
- package/dist/lib/machine-bootstrap-prompt.d.ts +17 -0
- package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -0
- package/dist/lib/machine-bootstrap-prompt.js +426 -0
- package/dist/lib/machine-bootstrap-prompt.js.map +1 -0
- package/dist/lib/machine-projects.d.ts +71 -0
- package/dist/lib/machine-projects.d.ts.map +1 -0
- package/dist/lib/machine-projects.js +510 -0
- package/dist/lib/machine-projects.js.map +1 -0
- package/dist/lib/machine-verify.d.ts +175 -0
- package/dist/lib/machine-verify.d.ts.map +1 -0
- package/dist/lib/machine-verify.js +684 -0
- package/dist/lib/machine-verify.js.map +1 -0
- package/dist/lib/portfolio-audit.d.ts +34 -0
- package/dist/lib/portfolio-audit.d.ts.map +1 -0
- package/dist/lib/portfolio-audit.js +254 -0
- package/dist/lib/portfolio-audit.js.map +1 -0
- package/dist/lib/portfolio-graph.d.ts +104 -0
- package/dist/lib/portfolio-graph.d.ts.map +1 -0
- package/dist/lib/portfolio-graph.js +281 -0
- package/dist/lib/portfolio-graph.js.map +1 -0
- package/dist/lib/project-strategy.d.ts +45 -0
- package/dist/lib/project-strategy.d.ts.map +1 -0
- package/dist/lib/project-strategy.js +234 -0
- package/dist/lib/project-strategy.js.map +1 -0
- package/dist/lib/realtime-sync.d.ts +128 -0
- package/dist/lib/realtime-sync.d.ts.map +1 -0
- package/dist/lib/realtime-sync.js +215 -0
- package/dist/lib/realtime-sync.js.map +1 -0
- package/dist/lib/reusable-patterns.d.ts +30 -0
- package/dist/lib/reusable-patterns.d.ts.map +1 -0
- package/dist/lib/reusable-patterns.js +375 -0
- package/dist/lib/reusable-patterns.js.map +1 -0
- package/dist/lib/skill-catalog.d.ts.map +1 -1
- package/dist/lib/skill-catalog.js +20 -0
- package/dist/lib/skill-catalog.js.map +1 -1
- package/dist/lib/skills.d.ts +1 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +43 -13
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +63 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/mcp/registry.d.ts +5 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +426 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +50 -5
- package/dist/mcp/server.js.map +1 -1
- package/package.json +2 -1
- package/scripts/env-vault/README.md +21 -2
- package/scripts/env-vault/backup.sh +24 -1
- package/scripts/env-vault/restore.sh +123 -8
- package/scripts/skillstack-sync/README.md +35 -10
- package/scripts/skillstack-sync/bootstrap-new-mac.sh +31 -0
- package/scripts/skillstack-sync/capture-agent-config.sh +1 -0
- package/scripts/skillstack-sync/com.youmd.context-sync.plist +38 -0
- package/scripts/skillstack-sync/com.youmd.identity-sync.plist +3 -1
- package/scripts/skillstack-sync/com.youmd.realtime-sync.plist +35 -0
- package/scripts/skillstack-sync/com.youmd.skillstack-sync.plist +1 -1
- package/scripts/skillstack-sync/context-sync.sh +69 -1
- package/scripts/skillstack-sync/install-daemons.sh +10 -3
- package/skills/machine-bootstrap.md +312 -0
|
@@ -28,6 +28,9 @@ top of `backup.sh` and add the matching entry to `AGENT_AUTH_MAP` in
|
|
|
28
28
|
# via CLI (preferred — ships in the npm package)
|
|
29
29
|
youmd env backup
|
|
30
30
|
|
|
31
|
+
# Check local encryption tooling and env discovery without writing a vault:
|
|
32
|
+
youmd env backup --preflight
|
|
33
|
+
|
|
31
34
|
# or directly via bash (from the youmd repo root)
|
|
32
35
|
cd /Users/houstongolden/Desktop/CODE_2025/youmd
|
|
33
36
|
bash cli/scripts/env-vault/backup.sh
|
|
@@ -52,8 +55,13 @@ Do NOT transfer via unencrypted email or public Slack.
|
|
|
52
55
|
|
|
53
56
|
```bash
|
|
54
57
|
# Install dependencies first (e.g. Node, pnpm, etc.), then:
|
|
58
|
+
youmd env restore /path/to/env-vault-<date>.tar.<ext> --list
|
|
55
59
|
youmd env restore /path/to/env-vault-<date>.tar.<ext>
|
|
56
60
|
|
|
61
|
+
# Fresh-machine restore after repos have been cloned into CODE_YOU:
|
|
62
|
+
youmd env restore /path/to/env-vault-<date>.tar.<ext> --root ~/Desktop/CODE_YOU --list --map-existing --existing-only --skip-agent-auth
|
|
63
|
+
youmd env restore /path/to/env-vault-<date>.tar.<ext> --root ~/Desktop/CODE_YOU --map-existing --existing-only --skip-agent-auth
|
|
64
|
+
|
|
57
65
|
# If files already exist on the new Mac:
|
|
58
66
|
youmd env restore --force /path/to/env-vault-<date>.tar.<ext>
|
|
59
67
|
|
|
@@ -63,10 +71,15 @@ bash cli/scripts/env-vault/restore.sh --force /path/to/env-vault-<date>.tar.<ext
|
|
|
63
71
|
```
|
|
64
72
|
|
|
65
73
|
The script:
|
|
66
|
-
1.
|
|
67
|
-
2.
|
|
74
|
+
1. Lists vault contents without writing files when `--list` is provided.
|
|
75
|
+
2. Creates `<CODE_2025>/<project>/.env.local` for each project during restore.
|
|
76
|
+
3. Restores agent-auth files to their absolute home paths (`~/.codex/auth.json`, `~/.cursor/mcp.json`, `~/.claude.json`), creating parent directories as needed.
|
|
77
|
+
4. With `--map-existing`, maps archived project folder names onto existing target-root dirs by normalized name, e.g. `foldermd` -> `folder-md`.
|
|
78
|
+
5. With `--existing-only`, skips archived projects that do not already have a mapped target dir. This prevents fresh-machine restores from creating stale duplicate folders.
|
|
79
|
+
6. With `--skip-agent-auth`, restores only project `.env.local` files and leaves the new machine's active Claude/Codex/Cursor auth files untouched.
|
|
68
80
|
|
|
69
81
|
Existing files are backed up to `<path>.bak.<timestamp>` before overwrite (or silently overwritten with `--force`).
|
|
82
|
+
List mode prints project env target paths, variable names/counts, and agent-auth file presence only. It never prints secret values.
|
|
70
83
|
|
|
71
84
|
---
|
|
72
85
|
|
|
@@ -101,12 +114,16 @@ and are exposed as first-class CLI commands:
|
|
|
101
114
|
|
|
102
115
|
```bash
|
|
103
116
|
youmd env backup # back up all .env.local files
|
|
117
|
+
youmd env backup --preflight # verify tooling/discovery without writing
|
|
104
118
|
youmd env backup --root <dir> # custom search root
|
|
105
119
|
youmd env backup --out <dir> # custom output dir
|
|
106
120
|
|
|
107
121
|
youmd env restore <vault> # restore from an encrypted vault
|
|
122
|
+
youmd env restore <vault> --list # list vault contents without writing
|
|
108
123
|
youmd env restore --force # overwrite existing .env.local files
|
|
109
124
|
youmd env restore --root <dir> # restore into a custom root
|
|
125
|
+
youmd env restore <vault> --root ~/Desktop/CODE_YOU --map-existing --existing-only --skip-agent-auth
|
|
126
|
+
# safe fresh-machine restore into cloned project dirs
|
|
110
127
|
```
|
|
111
128
|
|
|
112
129
|
The CLI wrapper delegates directly to these bash scripts via `spawnSync` with
|
|
@@ -121,6 +138,7 @@ your terminal unchanged.
|
|
|
121
138
|
|
|
122
139
|
| Flag | Default | Description |
|
|
123
140
|
|------|---------|-------------|
|
|
141
|
+
| `--preflight` | off | Verify encryption tooling/discovery without writing a vault |
|
|
124
142
|
| `--root <dir>` | `~/Desktop/CODE_2025` | Where to discover `.env.local` files |
|
|
125
143
|
| `--out <dir>` | `youmd/.env-vault/` | Where to write encrypted vault + manifest |
|
|
126
144
|
|
|
@@ -128,6 +146,7 @@ your terminal unchanged.
|
|
|
128
146
|
|
|
129
147
|
| Flag | Default | Description |
|
|
130
148
|
|------|---------|-------------|
|
|
149
|
+
| `--list` | off | List vault contents without writing files |
|
|
131
150
|
| `--root <dir>` | `~/Desktop/CODE_2025` | Where to restore project `.env.local` files |
|
|
132
151
|
| `--force` | off | Overwrite existing `.env.local` instead of skipping |
|
|
133
152
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# echoes, logs, or writes any secret VALUE. Only variable NAMES, counts, and
|
|
5
5
|
# file paths appear in plaintext output.
|
|
6
6
|
#
|
|
7
|
-
# Usage: bash backup.sh [--root <search-root>] [--out <output-dir>]
|
|
7
|
+
# Usage: bash backup.sh [--preflight] [--root <search-root>] [--out <output-dir>]
|
|
8
8
|
# Defaults:
|
|
9
9
|
# search-root: /Users/houstongolden/Desktop/CODE_2025
|
|
10
10
|
# output-dir: /Users/houstongolden/Desktop/CODE_2025/youmd/.env-vault
|
|
@@ -14,6 +14,7 @@ set -euo pipefail
|
|
|
14
14
|
# ── configurable defaults ──────────────────────────────────────────────────────
|
|
15
15
|
SEARCH_ROOT="${ENV_VAULT_ROOT:-/Users/houstongolden/Desktop/CODE_2025}"
|
|
16
16
|
OUTPUT_DIR="${ENV_VAULT_OUT:-/Users/houstongolden/Desktop/CODE_2025/youmd/.env-vault}"
|
|
17
|
+
PREFLIGHT=false
|
|
17
18
|
|
|
18
19
|
# ── agent-auth secret files ────────────────────────────────────────────────────
|
|
19
20
|
# Absolute paths to hard agent-auth secrets that must travel with the vault.
|
|
@@ -28,6 +29,7 @@ AGENT_SECRET_FILES=(
|
|
|
28
29
|
# ── parse flags ────────────────────────────────────────────────────────────────
|
|
29
30
|
while [[ $# -gt 0 ]]; do
|
|
30
31
|
case $1 in
|
|
32
|
+
--preflight) PREFLIGHT=true; shift ;;
|
|
31
33
|
--root) SEARCH_ROOT="$2"; shift 2 ;;
|
|
32
34
|
--out) OUTPUT_DIR="$2"; shift 2 ;;
|
|
33
35
|
*) echo "Unknown flag: $1" >&2; exit 1 ;;
|
|
@@ -66,11 +68,32 @@ done < <(find "${SEARCH_ROOT}" -maxdepth 2 -name ".env.local" -print0 2>/dev/nul
|
|
|
66
68
|
|
|
67
69
|
if [[ ${#ENV_FILES[@]} -eq 0 ]]; then
|
|
68
70
|
echo "No .env.local files found under ${SEARCH_ROOT}" >&2
|
|
71
|
+
if [[ "${PREFLIGHT}" == "true" ]]; then
|
|
72
|
+
echo "Preflight only: encryption tooling is available, but no .env.local files were found."
|
|
73
|
+
exit 0
|
|
74
|
+
fi
|
|
69
75
|
exit 1
|
|
70
76
|
fi
|
|
71
77
|
|
|
72
78
|
echo "Found ${#ENV_FILES[@]} .env.local file(s)."
|
|
73
79
|
|
|
80
|
+
if [[ "${PREFLIGHT}" == "true" ]]; then
|
|
81
|
+
echo "Output dir: ${OUTPUT_DIR}"
|
|
82
|
+
echo "Agent-auth candidates:"
|
|
83
|
+
for ENTRY in "${AGENT_SECRET_FILES[@]}"; do
|
|
84
|
+
SRC_PATH="${ENTRY%%:*}"
|
|
85
|
+
ARCHIVE_NAME="${ENTRY##*:}"
|
|
86
|
+
if [[ -f "${SRC_PATH}" ]]; then
|
|
87
|
+
FILE_BYTES=$(wc -c < "${SRC_PATH}" | tr -d ' ')
|
|
88
|
+
echo " present: agent-auth/${ARCHIVE_NAME} (${FILE_BYTES} bytes)"
|
|
89
|
+
else
|
|
90
|
+
echo " missing: agent-auth/${ARCHIVE_NAME}"
|
|
91
|
+
fi
|
|
92
|
+
done
|
|
93
|
+
echo "Preflight only: no vault written and no secret values printed."
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
74
97
|
# ── build plaintext manifest (names + counts, NO values) ─────────────────────
|
|
75
98
|
mkdir -p "${OUTPUT_DIR}"
|
|
76
99
|
UTC_DATE="$(date -u +%Y-%m-%dT%H%MZ)"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# env-vault/restore.sh — restores .env.local files AND agent-auth secrets from
|
|
3
3
|
# an encrypted vault created by backup.sh. NEVER prints, echoes, or logs any
|
|
4
|
-
# secret VALUES.
|
|
4
|
+
# secret VALUES. Restore prints which file paths were restored or skipped; list
|
|
5
|
+
# mode prints target paths plus variable names/counts only.
|
|
5
6
|
#
|
|
6
|
-
# Usage: bash restore.sh [--force] [--
|
|
7
|
+
# Usage: bash restore.sh [--list] [--force] [--map-existing] [--existing-only]
|
|
8
|
+
# [--skip-agent-auth] [--root <target-root>] <vault-file>
|
|
7
9
|
# vault-file: path to env-vault-*.tar.age / .tar.gpg / .tar.enc
|
|
8
10
|
# --force: overwrite existing files without backing them up
|
|
9
11
|
# --root: destination root for .env.local files
|
|
@@ -29,14 +31,22 @@ AGENT_AUTH_MAP=(
|
|
|
29
31
|
# ── defaults ──────────────────────────────────────────────────────────────────
|
|
30
32
|
TARGET_ROOT="${ENV_VAULT_RESTORE_ROOT:-/Users/houstongolden/Desktop/CODE_2025}"
|
|
31
33
|
FORCE=false
|
|
34
|
+
LIST_ONLY=false
|
|
35
|
+
MAP_EXISTING=false
|
|
36
|
+
EXISTING_ONLY=false
|
|
37
|
+
SKIP_AGENT_AUTH=false
|
|
32
38
|
VAULT_FILE=""
|
|
33
39
|
|
|
34
40
|
# ── parse args ─────────────────────────────────────────────────────────────────
|
|
35
41
|
while [[ $# -gt 0 ]]; do
|
|
36
42
|
case $1 in
|
|
37
|
-
--
|
|
38
|
-
--
|
|
39
|
-
|
|
43
|
+
--list) LIST_ONLY=true; shift ;;
|
|
44
|
+
--force) FORCE=true; shift ;;
|
|
45
|
+
--map-existing) MAP_EXISTING=true; shift ;;
|
|
46
|
+
--existing-only) EXISTING_ONLY=true; shift ;;
|
|
47
|
+
--skip-agent-auth) SKIP_AGENT_AUTH=true; shift ;;
|
|
48
|
+
--root) TARGET_ROOT="$2"; shift 2 ;;
|
|
49
|
+
-*) echo "Unknown flag: $1" >&2; exit 1 ;;
|
|
40
50
|
*)
|
|
41
51
|
if [[ -z "${VAULT_FILE}" ]]; then
|
|
42
52
|
VAULT_FILE="$1"
|
|
@@ -49,7 +59,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
49
59
|
done
|
|
50
60
|
|
|
51
61
|
if [[ -z "${VAULT_FILE}" ]]; then
|
|
52
|
-
echo "Usage: bash restore.sh [--force] [--root <path>] <vault-file>" >&2
|
|
62
|
+
echo "Usage: bash restore.sh [--list] [--force] [--map-existing] [--existing-only] [--skip-agent-auth] [--root <path>] <vault-file>" >&2
|
|
53
63
|
echo " vault-file: env-vault-*.tar.age | .tar.gpg | .tar.enc" >&2
|
|
54
64
|
exit 1
|
|
55
65
|
fi
|
|
@@ -77,8 +87,53 @@ fi
|
|
|
77
87
|
echo "Encryption tool: ${ENC_TOOL}"
|
|
78
88
|
echo "Vault file: ${VAULT_FILE}"
|
|
79
89
|
echo "Target root: ${TARGET_ROOT}"
|
|
90
|
+
echo "Project mapping: map-existing=${MAP_EXISTING} existing-only=${EXISTING_ONLY}"
|
|
91
|
+
echo "Agent auth: $([[ "${SKIP_AGENT_AUTH}" == "true" ]] && echo "skip" || echo "restore")"
|
|
80
92
|
echo ""
|
|
81
93
|
|
|
94
|
+
normalize_project_name() {
|
|
95
|
+
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
map_project_name() {
|
|
99
|
+
local archive_name="$1"
|
|
100
|
+
local exact_dir="${TARGET_ROOT}/${archive_name}"
|
|
101
|
+
if [[ "${MAP_EXISTING}" != "true" ]]; then
|
|
102
|
+
printf '%s\n' "${archive_name}"
|
|
103
|
+
return 0
|
|
104
|
+
fi
|
|
105
|
+
if [[ -d "${exact_dir}" ]]; then
|
|
106
|
+
printf '%s\n' "${archive_name}"
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
local wanted
|
|
111
|
+
wanted="$(normalize_project_name "${archive_name}")"
|
|
112
|
+
local matches=()
|
|
113
|
+
local candidate
|
|
114
|
+
while IFS= read -r -d '' candidate; do
|
|
115
|
+
local base
|
|
116
|
+
base="$(basename "${candidate}")"
|
|
117
|
+
if [[ "$(normalize_project_name "${base}")" == "${wanted}" ]]; then
|
|
118
|
+
matches+=("${base}")
|
|
119
|
+
fi
|
|
120
|
+
done < <(find "${TARGET_ROOT}" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
|
|
121
|
+
|
|
122
|
+
if [[ "${#matches[@]}" -eq 1 ]]; then
|
|
123
|
+
printf '%s\n' "${matches[0]}"
|
|
124
|
+
return 0
|
|
125
|
+
fi
|
|
126
|
+
if [[ "${#matches[@]}" -gt 1 ]]; then
|
|
127
|
+
echo "WARN: multiple existing dirs match vault project '${archive_name}': ${matches[*]} — skipping" >&2
|
|
128
|
+
return 1
|
|
129
|
+
fi
|
|
130
|
+
if [[ "${EXISTING_ONLY}" == "true" ]]; then
|
|
131
|
+
echo "WARN: no existing dir for vault project '${archive_name}' under ${TARGET_ROOT} — skipping" >&2
|
|
132
|
+
return 1
|
|
133
|
+
fi
|
|
134
|
+
printf '%s\n' "${archive_name}"
|
|
135
|
+
}
|
|
136
|
+
|
|
82
137
|
# ── decrypt into a temp dir ────────────────────────────────────────────────────
|
|
83
138
|
WORK_DIR="$(mktemp -d)"
|
|
84
139
|
TAR_PATH="${WORK_DIR}/vault.tar"
|
|
@@ -119,6 +174,58 @@ EXTRACT_DIR="${WORK_DIR}/extracted"
|
|
|
119
174
|
mkdir -p "${EXTRACT_DIR}"
|
|
120
175
|
tar -xf "${TAR_PATH}" -C "${EXTRACT_DIR}"
|
|
121
176
|
|
|
177
|
+
if [[ "${LIST_ONLY}" == "true" ]]; then
|
|
178
|
+
ENV_COUNT=0
|
|
179
|
+
AGENT_PRESENT=0
|
|
180
|
+
AGENT_MISSING=0
|
|
181
|
+
|
|
182
|
+
echo "Vault contents (secret-safe inventory):"
|
|
183
|
+
while IFS= read -r -d '' ENV_FILE; do
|
|
184
|
+
REL_PATH="${ENV_FILE#${EXTRACT_DIR}/}"
|
|
185
|
+
ARCHIVE_PROJECT_NAME="$(dirname "${REL_PATH}")"
|
|
186
|
+
if ! PROJECT_NAME="$(map_project_name "${ARCHIVE_PROJECT_NAME}")"; then
|
|
187
|
+
echo " env: ${ARCHIVE_PROJECT_NAME}/.env.local -> SKIPPED (no safe target)"
|
|
188
|
+
(( ENV_COUNT++ )) || true
|
|
189
|
+
continue
|
|
190
|
+
fi
|
|
191
|
+
DEST="${TARGET_ROOT}/${PROJECT_NAME}/.env.local"
|
|
192
|
+
VAR_COUNT=$(grep -cE '^[A-Za-z_][A-Za-z0-9_]*=' "${ENV_FILE}" 2>/dev/null || true)
|
|
193
|
+
VAR_NAMES=$(grep -oE '^[A-Za-z_][A-Za-z0-9_]*' "${ENV_FILE}" 2>/dev/null \
|
|
194
|
+
| grep -v '^$' | sort | paste -sd ',' - || true)
|
|
195
|
+
if [[ "${ARCHIVE_PROJECT_NAME}" == "${PROJECT_NAME}" ]]; then
|
|
196
|
+
echo " env: ${PROJECT_NAME}/.env.local -> ${DEST} (${VAR_COUNT} variable(s) [${VAR_NAMES}])"
|
|
197
|
+
else
|
|
198
|
+
echo " env: ${ARCHIVE_PROJECT_NAME}/.env.local -> ${DEST} (${VAR_COUNT} variable(s) [${VAR_NAMES}])"
|
|
199
|
+
fi
|
|
200
|
+
(( ENV_COUNT++ )) || true
|
|
201
|
+
done < <(find "${EXTRACT_DIR}" -name ".env.local" -print0)
|
|
202
|
+
|
|
203
|
+
AGENT_AUTH_SRC="${EXTRACT_DIR}/agent-auth"
|
|
204
|
+
echo " agent-auth:"
|
|
205
|
+
if [[ "${SKIP_AGENT_AUTH}" == "true" ]]; then
|
|
206
|
+
echo " skipped by --skip-agent-auth"
|
|
207
|
+
else
|
|
208
|
+
for ENTRY in "${AGENT_AUTH_MAP[@]}"; do
|
|
209
|
+
ARCHIVE_NAME="${ENTRY%%:*}"
|
|
210
|
+
DEST_PATH="${ENTRY##*:}"
|
|
211
|
+
SRC_FILE="${AGENT_AUTH_SRC}/${ARCHIVE_NAME}"
|
|
212
|
+
if [[ -f "${SRC_FILE}" ]]; then
|
|
213
|
+
FILE_BYTES=$(wc -c < "${SRC_FILE}" | tr -d ' ')
|
|
214
|
+
echo " present: agent-auth/${ARCHIVE_NAME} -> ${DEST_PATH} (${FILE_BYTES} bytes)"
|
|
215
|
+
(( AGENT_PRESENT++ )) || true
|
|
216
|
+
else
|
|
217
|
+
echo " missing: agent-auth/${ARCHIVE_NAME}"
|
|
218
|
+
(( AGENT_MISSING++ )) || true
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
echo ""
|
|
224
|
+
echo "List summary: ${ENV_COUNT} .env.local file(s), ${AGENT_PRESENT} agent-auth file(s) present, ${AGENT_MISSING} agent-auth file(s) missing."
|
|
225
|
+
echo "No files were written and no secret values were printed."
|
|
226
|
+
exit 0
|
|
227
|
+
fi
|
|
228
|
+
|
|
122
229
|
# ── restore each .env.local ───────────────────────────────────────────────────
|
|
123
230
|
RESTORED=0
|
|
124
231
|
SKIPPED=0
|
|
@@ -127,7 +234,12 @@ BACKED_UP=0
|
|
|
127
234
|
while IFS= read -r -d '' ENV_FILE; do
|
|
128
235
|
# ENV_FILE is relative to EXTRACT_DIR, e.g. ./project-name/.env.local
|
|
129
236
|
REL_PATH="${ENV_FILE#${EXTRACT_DIR}/}" # project-name/.env.local
|
|
130
|
-
|
|
237
|
+
ARCHIVE_PROJECT_NAME="$(dirname "${REL_PATH}")" # project-name
|
|
238
|
+
if ! PROJECT_NAME="$(map_project_name "${ARCHIVE_PROJECT_NAME}")"; then
|
|
239
|
+
echo " SKIPPED (no existing mapped target): ${ARCHIVE_PROJECT_NAME}/.env.local"
|
|
240
|
+
(( SKIPPED++ )) || true
|
|
241
|
+
continue
|
|
242
|
+
fi
|
|
131
243
|
DEST="${TARGET_ROOT}/${PROJECT_NAME}/.env.local"
|
|
132
244
|
DEST_DIR="$(dirname "${DEST}")"
|
|
133
245
|
|
|
@@ -162,7 +274,10 @@ AGENT_BACKED_UP=0
|
|
|
162
274
|
|
|
163
275
|
AGENT_AUTH_SRC="${EXTRACT_DIR}/agent-auth"
|
|
164
276
|
|
|
165
|
-
if [[
|
|
277
|
+
if [[ "${SKIP_AGENT_AUTH}" == "true" ]]; then
|
|
278
|
+
echo "Skipping agent-auth restore because --skip-agent-auth was provided."
|
|
279
|
+
echo ""
|
|
280
|
+
elif [[ -d "${AGENT_AUTH_SRC}" ]]; then
|
|
166
281
|
echo "Restoring agent-auth files…"
|
|
167
282
|
for ENTRY in "${AGENT_AUTH_MAP[@]}"; do
|
|
168
283
|
ARCHIVE_NAME="${ENTRY%%:*}"
|
|
@@ -28,7 +28,9 @@ Cross-machine sync toolkit for Houston Golden's agent skill/stack setup.
|
|
|
28
28
|
|
|
29
29
|
### Complementary sync planes
|
|
30
30
|
|
|
31
|
-
- **
|
|
31
|
+
- **Realtime identity/project plane:** `youmd sync --live --daemon` subscribes to Convex websocket updates, mints only a short-lived sync session token, materializes identity files and installed You.md skills locally, and triggers bounded shared stack/project-context syncs. It never prints or returns raw `.env.local` values.
|
|
32
|
+
- **Identity repair plane:** `youmd sync --daemon` (Convex ↔ local profile, memories, preferences). Automated via `com.youmd.identity-sync` daemon as a timer-based fallback. Daemon mode refreshes local files/skills and skips unsafe lossy pushes instead of forcing over richer server data.
|
|
33
|
+
- **Project-context plane:** `youmd stack context-sync` safely commits and syncs only `AGENTS.md`, `CLAUDE.md`, `project-context/`, and `.claude/` in curated Houston-owned repos. It refuses to merge remote app-code changes.
|
|
32
34
|
- **Env-vault plane:** `cli/scripts/env-vault/restore.sh` for secrets (manual, invoked on new machine); also available as `youmd env restore <vault>`.
|
|
33
35
|
|
|
34
36
|
---
|
|
@@ -38,10 +40,12 @@ Cross-machine sync toolkit for Houston Golden's agent skill/stack setup.
|
|
|
38
40
|
```
|
|
39
41
|
cli/scripts/skillstack-sync/
|
|
40
42
|
├── sync.sh Core syncer (bash 3.2 compatible)
|
|
41
|
-
├── install-daemons.sh Installs
|
|
43
|
+
├── install-daemons.sh Installs all resident LaunchAgents
|
|
42
44
|
├── bootstrap-new-mac.sh New machine setup script
|
|
45
|
+
├── com.youmd.realtime-sync.plist LaunchAgent: runs `youmd sync --live --daemon` as a resident websocket syncer
|
|
43
46
|
├── com.youmd.skillstack-sync.plist LaunchAgent: runs `youmd stack sync` every 5 min
|
|
44
|
-
├── com.youmd.identity-sync.plist LaunchAgent: runs `youmd sync` every 5 min
|
|
47
|
+
├── com.youmd.identity-sync.plist LaunchAgent: runs `youmd sync --daemon` every 5 min
|
|
48
|
+
├── com.youmd.context-sync.plist LaunchAgent: runs `youmd stack context-sync` every 15 min
|
|
45
49
|
└── README.md This file
|
|
46
50
|
```
|
|
47
51
|
|
|
@@ -90,7 +94,7 @@ GIT_USER_EMAIL="houston@bamf.ai" # commit email (default)
|
|
|
90
94
|
The preferred way is via the CLI:
|
|
91
95
|
|
|
92
96
|
```bash
|
|
93
|
-
youmd stack daemon install # installs
|
|
97
|
+
youmd stack daemon install # installs all resident LaunchAgents
|
|
94
98
|
youmd stack daemon status # check loaded/not-loaded
|
|
95
99
|
youmd stack daemon uninstall # remove plists from ~/Library/LaunchAgents/
|
|
96
100
|
```
|
|
@@ -101,16 +105,20 @@ Or run the raw script directly:
|
|
|
101
105
|
bash cli/scripts/skillstack-sync/install-daemons.sh
|
|
102
106
|
```
|
|
103
107
|
|
|
104
|
-
Installs
|
|
108
|
+
Installs four LaunchAgents:
|
|
109
|
+
- `com.youmd.realtime-sync` → runs `youmd sync --live --daemon`
|
|
105
110
|
- `com.youmd.skillstack-sync` → runs `youmd stack sync`
|
|
106
|
-
- `com.youmd.identity-sync` → runs `youmd sync`
|
|
111
|
+
- `com.youmd.identity-sync` → runs `youmd sync --daemon`
|
|
112
|
+
- `com.youmd.context-sync` → runs `youmd stack context-sync`
|
|
107
113
|
|
|
108
114
|
Check status:
|
|
109
115
|
```bash
|
|
110
116
|
youmd stack daemon status
|
|
111
117
|
# or directly:
|
|
112
118
|
launchctl list com.youmd.skillstack-sync
|
|
119
|
+
launchctl list com.youmd.realtime-sync
|
|
113
120
|
launchctl list com.youmd.identity-sync
|
|
121
|
+
launchctl list com.youmd.context-sync
|
|
114
122
|
```
|
|
115
123
|
|
|
116
124
|
Check logs:
|
|
@@ -118,6 +126,7 @@ Check logs:
|
|
|
118
126
|
tail -f ~/.youmd/logs/skillstack-sync.log
|
|
119
127
|
tail -f ~/.youmd/logs/skillstack-sync.out.log
|
|
120
128
|
tail -f ~/.youmd/logs/identity-sync.out.log
|
|
129
|
+
tail -f ~/.youmd/logs/context-sync.log
|
|
121
130
|
```
|
|
122
131
|
|
|
123
132
|
### Uninstall daemons
|
|
@@ -130,27 +139,43 @@ Or manually:
|
|
|
130
139
|
```bash
|
|
131
140
|
launchctl unload ~/Library/LaunchAgents/com.youmd.skillstack-sync.plist
|
|
132
141
|
launchctl unload ~/Library/LaunchAgents/com.youmd.identity-sync.plist
|
|
142
|
+
launchctl unload ~/Library/LaunchAgents/com.youmd.context-sync.plist
|
|
133
143
|
rm ~/Library/LaunchAgents/com.youmd.skillstack-sync.plist
|
|
134
144
|
rm ~/Library/LaunchAgents/com.youmd.identity-sync.plist
|
|
145
|
+
rm ~/Library/LaunchAgents/com.youmd.context-sync.plist
|
|
135
146
|
```
|
|
136
147
|
|
|
137
148
|
---
|
|
138
149
|
|
|
139
150
|
## New Mac setup
|
|
140
151
|
|
|
152
|
+
Preferred path: open the You.md Machine tab on an authenticated source computer,
|
|
153
|
+
copy the fresh-machine Claude/Codex setup prompt, and paste it into Claude Code
|
|
154
|
+
or Codex on the new Mac. That generated prompt checks/install Homebrew, Node 22,
|
|
155
|
+
GitHub CLI, bun, and pnpm; authenticates You.md; requires GitHub auth before
|
|
156
|
+
private clones; clones only setup-eligible active projects into
|
|
157
|
+
`~/Desktop/CODE_YOU`; restores env files with `--map-existing --existing-only
|
|
158
|
+
--skip-agent-auth`; and installs resident daemons.
|
|
159
|
+
|
|
160
|
+
Fallback manual path:
|
|
161
|
+
|
|
141
162
|
```bash
|
|
142
163
|
# 1. Install youmd CLI
|
|
143
164
|
curl -fsSL https://you.md/install.sh | bash
|
|
144
165
|
|
|
145
|
-
# 2.
|
|
166
|
+
# 2. Authenticate GitHub before private stack/project clones
|
|
167
|
+
gh auth login -h github.com -p https -s repo
|
|
168
|
+
|
|
169
|
+
# 3. Clone this repo (youmd)
|
|
146
170
|
git clone https://github.com/houstongolden/youmd ~/Desktop/CODE_2025/youmd
|
|
147
171
|
|
|
148
|
-
#
|
|
172
|
+
# 4. Run bootstrap (clones agent-shared + scistack)
|
|
149
173
|
bash ~/Desktop/CODE_2025/youmd/cli/scripts/skillstack-sync/bootstrap-new-mac.sh
|
|
150
174
|
|
|
151
|
-
#
|
|
175
|
+
# 5. Restore project env files from env-vault (manual step — see env-vault/README)
|
|
176
|
+
youmd env restore <vault> --root ~/Desktop/CODE_YOU --map-existing --existing-only --skip-agent-auth
|
|
152
177
|
|
|
153
|
-
#
|
|
178
|
+
# 6. Activate daemons
|
|
154
179
|
youmd stack daemon install
|
|
155
180
|
```
|
|
156
181
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
# Usage: bash bootstrap-new-mac.sh
|
|
11
11
|
|
|
12
12
|
set -euo pipefail
|
|
13
|
+
export PATH="${HOME}/.youmd/bin:${HOME}/.youmd/npm-global/bin:/opt/homebrew/opt/node@22/bin:/usr/local/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:${PATH}"
|
|
13
14
|
|
|
14
15
|
AGENT_SHARED="${HOME}/.agent-shared"
|
|
15
16
|
SCISTACK="${HOME}/.claude/scistack"
|
|
@@ -33,6 +34,34 @@ warn() {
|
|
|
33
34
|
echo " WARN: $*"
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
ensure_github_auth() {
|
|
38
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
39
|
+
warn "GitHub CLI is missing. Install it with Homebrew first: brew install gh"
|
|
40
|
+
return 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
if gh auth status >/dev/null 2>&1; then
|
|
44
|
+
info "GitHub auth ready."
|
|
45
|
+
return 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
warn "GitHub auth is required before private skill/stack repos can clone."
|
|
49
|
+
if [ -t 0 ]; then
|
|
50
|
+
gh auth login -h github.com -p https -s repo || true
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if gh auth status >/dev/null 2>&1; then
|
|
54
|
+
info "GitHub auth ready."
|
|
55
|
+
return 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
warn "GitHub auth still is not complete."
|
|
59
|
+
warn "Open a normal Terminal and run:"
|
|
60
|
+
warn " $(command -v gh || echo gh) auth login -h github.com -p https -s repo"
|
|
61
|
+
warn "Then rerun: youmd machine setup"
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
36
65
|
# ---------------------------------------------------------------------------
|
|
37
66
|
step "1. Install youmd CLI"
|
|
38
67
|
# ---------------------------------------------------------------------------
|
|
@@ -47,6 +76,8 @@ fi
|
|
|
47
76
|
# ---------------------------------------------------------------------------
|
|
48
77
|
step "2. Clone agent-shared repo → ${AGENT_SHARED}"
|
|
49
78
|
# ---------------------------------------------------------------------------
|
|
79
|
+
ensure_github_auth
|
|
80
|
+
|
|
50
81
|
if [ -d "${AGENT_SHARED}/.git" ]; then
|
|
51
82
|
info "Already present: ${AGENT_SHARED} — skipping clone."
|
|
52
83
|
else
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.youmd.context-sync</string>
|
|
7
|
+
|
|
8
|
+
<key>ProgramArguments</key>
|
|
9
|
+
<array>
|
|
10
|
+
<string>/bin/zsh</string>
|
|
11
|
+
<string>-lc</string>
|
|
12
|
+
<string>youmd stack context-sync</string>
|
|
13
|
+
</array>
|
|
14
|
+
|
|
15
|
+
<key>StartInterval</key>
|
|
16
|
+
<integer>900</integer>
|
|
17
|
+
|
|
18
|
+
<key>RunAtLoad</key>
|
|
19
|
+
<true/>
|
|
20
|
+
|
|
21
|
+
<key>KeepAlive</key>
|
|
22
|
+
<false/>
|
|
23
|
+
|
|
24
|
+
<key>StandardOutPath</key>
|
|
25
|
+
<string>__HOME__/.youmd/logs/context-sync.out.log</string>
|
|
26
|
+
|
|
27
|
+
<key>StandardErrorPath</key>
|
|
28
|
+
<string>__HOME__/.youmd/logs/context-sync.err.log</string>
|
|
29
|
+
|
|
30
|
+
<key>EnvironmentVariables</key>
|
|
31
|
+
<dict>
|
|
32
|
+
<key>HOME</key>
|
|
33
|
+
<string>__HOME__</string>
|
|
34
|
+
<key>PATH</key>
|
|
35
|
+
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
36
|
+
</dict>
|
|
37
|
+
</dict>
|
|
38
|
+
</plist>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<array>
|
|
10
10
|
<string>/bin/zsh</string>
|
|
11
11
|
<string>-lc</string>
|
|
12
|
-
<string>youmd sync</string>
|
|
12
|
+
<string>youmd sync --daemon</string>
|
|
13
13
|
</array>
|
|
14
14
|
|
|
15
15
|
<key>StartInterval</key>
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
<dict>
|
|
32
32
|
<key>HOME</key>
|
|
33
33
|
<string>__HOME__</string>
|
|
34
|
+
<key>PATH</key>
|
|
35
|
+
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
34
36
|
</dict>
|
|
35
37
|
</dict>
|
|
36
38
|
</plist>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.youmd.realtime-sync</string>
|
|
7
|
+
|
|
8
|
+
<key>ProgramArguments</key>
|
|
9
|
+
<array>
|
|
10
|
+
<string>/bin/zsh</string>
|
|
11
|
+
<string>-lc</string>
|
|
12
|
+
<string>youmd sync --live --daemon</string>
|
|
13
|
+
</array>
|
|
14
|
+
|
|
15
|
+
<key>RunAtLoad</key>
|
|
16
|
+
<true/>
|
|
17
|
+
|
|
18
|
+
<key>KeepAlive</key>
|
|
19
|
+
<true/>
|
|
20
|
+
|
|
21
|
+
<key>StandardOutPath</key>
|
|
22
|
+
<string>__HOME__/.youmd/logs/realtime-sync.out.log</string>
|
|
23
|
+
|
|
24
|
+
<key>StandardErrorPath</key>
|
|
25
|
+
<string>__HOME__/.youmd/logs/realtime-sync.err.log</string>
|
|
26
|
+
|
|
27
|
+
<key>EnvironmentVariables</key>
|
|
28
|
+
<dict>
|
|
29
|
+
<key>HOME</key>
|
|
30
|
+
<string>__HOME__</string>
|
|
31
|
+
<key>PATH</key>
|
|
32
|
+
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
33
|
+
</dict>
|
|
34
|
+
</dict>
|
|
35
|
+
</plist>
|