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.
Files changed (121) hide show
  1. package/dist/commands/chat.d.ts.map +1 -1
  2. package/dist/commands/chat.js +20 -2
  3. package/dist/commands/chat.js.map +1 -1
  4. package/dist/commands/env.d.ts +21 -4
  5. package/dist/commands/env.d.ts.map +1 -1
  6. package/dist/commands/env.js +250 -24
  7. package/dist/commands/env.js.map +1 -1
  8. package/dist/commands/login.d.ts +1 -0
  9. package/dist/commands/login.d.ts.map +1 -1
  10. package/dist/commands/login.js +20 -4
  11. package/dist/commands/login.js.map +1 -1
  12. package/dist/commands/machine.d.ts +28 -1
  13. package/dist/commands/machine.d.ts.map +1 -1
  14. package/dist/commands/machine.js +529 -4
  15. package/dist/commands/machine.js.map +1 -1
  16. package/dist/commands/project.d.ts.map +1 -1
  17. package/dist/commands/project.js +862 -17
  18. package/dist/commands/project.js.map +1 -1
  19. package/dist/commands/prompts.d.ts +19 -0
  20. package/dist/commands/prompts.d.ts.map +1 -1
  21. package/dist/commands/prompts.js +304 -1
  22. package/dist/commands/prompts.js.map +1 -1
  23. package/dist/commands/pull.d.ts.map +1 -1
  24. package/dist/commands/pull.js +28 -8
  25. package/dist/commands/pull.js.map +1 -1
  26. package/dist/commands/push.d.ts +3 -1
  27. package/dist/commands/push.d.ts.map +1 -1
  28. package/dist/commands/push.js +26 -12
  29. package/dist/commands/push.js.map +1 -1
  30. package/dist/commands/skill.d.ts.map +1 -1
  31. package/dist/commands/skill.js +19 -15
  32. package/dist/commands/skill.js.map +1 -1
  33. package/dist/commands/stack.d.ts.map +1 -1
  34. package/dist/commands/stack.js +20 -17
  35. package/dist/commands/stack.js.map +1 -1
  36. package/dist/commands/status.d.ts.map +1 -1
  37. package/dist/commands/status.js +38 -0
  38. package/dist/commands/status.js.map +1 -1
  39. package/dist/commands/sync.d.ts +2 -0
  40. package/dist/commands/sync.d.ts.map +1 -1
  41. package/dist/commands/sync.js +235 -2
  42. package/dist/commands/sync.js.map +1 -1
  43. package/dist/index.js +157 -31
  44. package/dist/index.js.map +1 -1
  45. package/dist/lib/api.d.ts +398 -0
  46. package/dist/lib/api.d.ts.map +1 -1
  47. package/dist/lib/api.js +104 -0
  48. package/dist/lib/api.js.map +1 -1
  49. package/dist/lib/daemon.d.ts +26 -0
  50. package/dist/lib/daemon.d.ts.map +1 -0
  51. package/dist/lib/daemon.js +187 -0
  52. package/dist/lib/daemon.js.map +1 -0
  53. package/dist/lib/first-run.d.ts +1 -1
  54. package/dist/lib/first-run.d.ts.map +1 -1
  55. package/dist/lib/first-run.js +8 -0
  56. package/dist/lib/first-run.js.map +1 -1
  57. package/dist/lib/machine-bootstrap-prompt.d.ts +17 -0
  58. package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -0
  59. package/dist/lib/machine-bootstrap-prompt.js +426 -0
  60. package/dist/lib/machine-bootstrap-prompt.js.map +1 -0
  61. package/dist/lib/machine-projects.d.ts +71 -0
  62. package/dist/lib/machine-projects.d.ts.map +1 -0
  63. package/dist/lib/machine-projects.js +510 -0
  64. package/dist/lib/machine-projects.js.map +1 -0
  65. package/dist/lib/machine-verify.d.ts +175 -0
  66. package/dist/lib/machine-verify.d.ts.map +1 -0
  67. package/dist/lib/machine-verify.js +684 -0
  68. package/dist/lib/machine-verify.js.map +1 -0
  69. package/dist/lib/portfolio-audit.d.ts +34 -0
  70. package/dist/lib/portfolio-audit.d.ts.map +1 -0
  71. package/dist/lib/portfolio-audit.js +254 -0
  72. package/dist/lib/portfolio-audit.js.map +1 -0
  73. package/dist/lib/portfolio-graph.d.ts +104 -0
  74. package/dist/lib/portfolio-graph.d.ts.map +1 -0
  75. package/dist/lib/portfolio-graph.js +281 -0
  76. package/dist/lib/portfolio-graph.js.map +1 -0
  77. package/dist/lib/project-strategy.d.ts +45 -0
  78. package/dist/lib/project-strategy.d.ts.map +1 -0
  79. package/dist/lib/project-strategy.js +234 -0
  80. package/dist/lib/project-strategy.js.map +1 -0
  81. package/dist/lib/realtime-sync.d.ts +128 -0
  82. package/dist/lib/realtime-sync.d.ts.map +1 -0
  83. package/dist/lib/realtime-sync.js +215 -0
  84. package/dist/lib/realtime-sync.js.map +1 -0
  85. package/dist/lib/reusable-patterns.d.ts +30 -0
  86. package/dist/lib/reusable-patterns.d.ts.map +1 -0
  87. package/dist/lib/reusable-patterns.js +375 -0
  88. package/dist/lib/reusable-patterns.js.map +1 -0
  89. package/dist/lib/skill-catalog.d.ts.map +1 -1
  90. package/dist/lib/skill-catalog.js +20 -0
  91. package/dist/lib/skill-catalog.js.map +1 -1
  92. package/dist/lib/skills.d.ts +1 -0
  93. package/dist/lib/skills.d.ts.map +1 -1
  94. package/dist/lib/skills.js +43 -13
  95. package/dist/lib/skills.js.map +1 -1
  96. package/dist/lib/version.d.ts +2 -0
  97. package/dist/lib/version.d.ts.map +1 -0
  98. package/dist/lib/version.js +63 -0
  99. package/dist/lib/version.js.map +1 -0
  100. package/dist/mcp/registry.d.ts +5 -1
  101. package/dist/mcp/registry.d.ts.map +1 -1
  102. package/dist/mcp/registry.js +426 -2
  103. package/dist/mcp/registry.js.map +1 -1
  104. package/dist/mcp/server.d.ts +2 -0
  105. package/dist/mcp/server.d.ts.map +1 -1
  106. package/dist/mcp/server.js +50 -5
  107. package/dist/mcp/server.js.map +1 -1
  108. package/package.json +2 -1
  109. package/scripts/env-vault/README.md +21 -2
  110. package/scripts/env-vault/backup.sh +24 -1
  111. package/scripts/env-vault/restore.sh +123 -8
  112. package/scripts/skillstack-sync/README.md +35 -10
  113. package/scripts/skillstack-sync/bootstrap-new-mac.sh +31 -0
  114. package/scripts/skillstack-sync/capture-agent-config.sh +1 -0
  115. package/scripts/skillstack-sync/com.youmd.context-sync.plist +38 -0
  116. package/scripts/skillstack-sync/com.youmd.identity-sync.plist +3 -1
  117. package/scripts/skillstack-sync/com.youmd.realtime-sync.plist +35 -0
  118. package/scripts/skillstack-sync/com.youmd.skillstack-sync.plist +1 -1
  119. package/scripts/skillstack-sync/context-sync.sh +69 -1
  120. package/scripts/skillstack-sync/install-daemons.sh +10 -3
  121. 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. 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.
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. Only prints which file paths were restored or skipped.
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] [--root <target-root>] <vault-file>
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
- --force) FORCE=true; shift ;;
38
- --root) TARGET_ROOT="$2"; shift 2 ;;
39
- -*) echo "Unknown flag: $1" >&2; exit 1 ;;
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
- PROJECT_NAME="$(dirname "${REL_PATH}")" # project-name
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 [[ -d "${AGENT_AUTH_SRC}" ]]; then
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
- - **Identity plane:** `youmd sync` (Convex ↔ local profile, memories, preferences). Automated via `com.youmd.identity-sync` daemon.
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 both LaunchAgents
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 both LaunchAgents
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 two LaunchAgents that fire every 300 seconds (5 minutes):
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. Clone this repo (youmd)
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
- # 3. Run bootstrap (clones agent-shared + scistack)
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
- # 4. Restore secrets from env-vault (manual step — see env-vault/README)
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
- # 5. Activate daemons
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
@@ -85,6 +85,7 @@ capture_plist() {
85
85
  }
86
86
  capture_plist "com.youmd.skillstack-sync"
87
87
  capture_plist "com.youmd.identity-sync"
88
+ capture_plist "com.youmd.context-sync"
88
89
  capture_plist "com.houstongolden.agent-runtime-guard"
89
90
 
90
91
  if ! is_dry; then
@@ -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>
@@ -32,7 +32,7 @@
32
32
  <key>HOME</key>
33
33
  <string>__HOME__</string>
34
34
  <key>PATH</key>
35
- <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
35
+ <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
36
36
  </dict>
37
37
  </dict>
38
38
  </plist>