youmd 0.8.0 → 0.8.2
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 +3 -2
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/env.d.ts +2 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +7 -3
- 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 +14 -17
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +31 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.js +119 -29
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +324 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +68 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/daemon.d.ts +23 -0
- package/dist/lib/daemon.d.ts.map +1 -0
- package/dist/lib/daemon.js +166 -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 +305 -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/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 +1 -1
- package/scripts/env-vault/README.md +12 -2
- package/scripts/env-vault/backup.sh +24 -1
- package/scripts/env-vault/restore.sh +45 -3
- package/scripts/skillstack-sync/README.md +13 -6
- 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.skillstack-sync.plist +1 -1
- package/scripts/skillstack-sync/context-sync.sh +69 -1
- package/scripts/skillstack-sync/install-daemons.sh +7 -3
- package/skills/machine-bootstrap.md +243 -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,6 +55,7 @@ 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
|
|
|
57
61
|
# If files already exist on the new Mac:
|
|
@@ -63,10 +67,12 @@ bash cli/scripts/env-vault/restore.sh --force /path/to/env-vault-<date>.tar.<ext
|
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
The script:
|
|
66
|
-
1.
|
|
67
|
-
2.
|
|
70
|
+
1. Lists vault contents without writing files when `--list` is provided.
|
|
71
|
+
2. Creates `<CODE_2025>/<project>/.env.local` for each project during restore.
|
|
72
|
+
3. Restores agent-auth files to their absolute home paths (`~/.codex/auth.json`, `~/.cursor/mcp.json`, `~/.claude.json`), creating parent directories as needed.
|
|
68
73
|
|
|
69
74
|
Existing files are backed up to `<path>.bak.<timestamp>` before overwrite (or silently overwritten with `--force`).
|
|
75
|
+
List mode prints project env target paths, variable names/counts, and agent-auth file presence only. It never prints secret values.
|
|
70
76
|
|
|
71
77
|
---
|
|
72
78
|
|
|
@@ -101,10 +107,12 @@ and are exposed as first-class CLI commands:
|
|
|
101
107
|
|
|
102
108
|
```bash
|
|
103
109
|
youmd env backup # back up all .env.local files
|
|
110
|
+
youmd env backup --preflight # verify tooling/discovery without writing
|
|
104
111
|
youmd env backup --root <dir> # custom search root
|
|
105
112
|
youmd env backup --out <dir> # custom output dir
|
|
106
113
|
|
|
107
114
|
youmd env restore <vault> # restore from an encrypted vault
|
|
115
|
+
youmd env restore <vault> --list # list vault contents without writing
|
|
108
116
|
youmd env restore --force # overwrite existing .env.local files
|
|
109
117
|
youmd env restore --root <dir> # restore into a custom root
|
|
110
118
|
```
|
|
@@ -121,6 +129,7 @@ your terminal unchanged.
|
|
|
121
129
|
|
|
122
130
|
| Flag | Default | Description |
|
|
123
131
|
|------|---------|-------------|
|
|
132
|
+
| `--preflight` | off | Verify encryption tooling/discovery without writing a vault |
|
|
124
133
|
| `--root <dir>` | `~/Desktop/CODE_2025` | Where to discover `.env.local` files |
|
|
125
134
|
| `--out <dir>` | `youmd/.env-vault/` | Where to write encrypted vault + manifest |
|
|
126
135
|
|
|
@@ -128,6 +137,7 @@ your terminal unchanged.
|
|
|
128
137
|
|
|
129
138
|
| Flag | Default | Description |
|
|
130
139
|
|------|---------|-------------|
|
|
140
|
+
| `--list` | off | List vault contents without writing files |
|
|
131
141
|
| `--root <dir>` | `~/Desktop/CODE_2025` | Where to restore project `.env.local` files |
|
|
132
142
|
| `--force` | off | Overwrite existing `.env.local` instead of skipping |
|
|
133
143
|
|
|
@@ -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,10 @@
|
|
|
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] [--root <target-root>] <vault-file>
|
|
7
|
+
# Usage: bash restore.sh [--list] [--force] [--root <target-root>] <vault-file>
|
|
7
8
|
# vault-file: path to env-vault-*.tar.age / .tar.gpg / .tar.enc
|
|
8
9
|
# --force: overwrite existing files without backing them up
|
|
9
10
|
# --root: destination root for .env.local files
|
|
@@ -29,11 +30,13 @@ AGENT_AUTH_MAP=(
|
|
|
29
30
|
# ── defaults ──────────────────────────────────────────────────────────────────
|
|
30
31
|
TARGET_ROOT="${ENV_VAULT_RESTORE_ROOT:-/Users/houstongolden/Desktop/CODE_2025}"
|
|
31
32
|
FORCE=false
|
|
33
|
+
LIST_ONLY=false
|
|
32
34
|
VAULT_FILE=""
|
|
33
35
|
|
|
34
36
|
# ── parse args ─────────────────────────────────────────────────────────────────
|
|
35
37
|
while [[ $# -gt 0 ]]; do
|
|
36
38
|
case $1 in
|
|
39
|
+
--list) LIST_ONLY=true; shift ;;
|
|
37
40
|
--force) FORCE=true; shift ;;
|
|
38
41
|
--root) TARGET_ROOT="$2"; shift 2 ;;
|
|
39
42
|
-*) echo "Unknown flag: $1" >&2; exit 1 ;;
|
|
@@ -49,7 +52,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
49
52
|
done
|
|
50
53
|
|
|
51
54
|
if [[ -z "${VAULT_FILE}" ]]; then
|
|
52
|
-
echo "Usage: bash restore.sh [--force] [--root <path>] <vault-file>" >&2
|
|
55
|
+
echo "Usage: bash restore.sh [--list] [--force] [--root <path>] <vault-file>" >&2
|
|
53
56
|
echo " vault-file: env-vault-*.tar.age | .tar.gpg | .tar.enc" >&2
|
|
54
57
|
exit 1
|
|
55
58
|
fi
|
|
@@ -119,6 +122,45 @@ EXTRACT_DIR="${WORK_DIR}/extracted"
|
|
|
119
122
|
mkdir -p "${EXTRACT_DIR}"
|
|
120
123
|
tar -xf "${TAR_PATH}" -C "${EXTRACT_DIR}"
|
|
121
124
|
|
|
125
|
+
if [[ "${LIST_ONLY}" == "true" ]]; then
|
|
126
|
+
ENV_COUNT=0
|
|
127
|
+
AGENT_PRESENT=0
|
|
128
|
+
AGENT_MISSING=0
|
|
129
|
+
|
|
130
|
+
echo "Vault contents (secret-safe inventory):"
|
|
131
|
+
while IFS= read -r -d '' ENV_FILE; do
|
|
132
|
+
REL_PATH="${ENV_FILE#${EXTRACT_DIR}/}"
|
|
133
|
+
PROJECT_NAME="$(dirname "${REL_PATH}")"
|
|
134
|
+
DEST="${TARGET_ROOT}/${PROJECT_NAME}/.env.local"
|
|
135
|
+
VAR_COUNT=$(grep -cE '^[A-Za-z_][A-Za-z0-9_]*=' "${ENV_FILE}" 2>/dev/null || true)
|
|
136
|
+
VAR_NAMES=$(grep -oE '^[A-Za-z_][A-Za-z0-9_]*' "${ENV_FILE}" 2>/dev/null \
|
|
137
|
+
| grep -v '^$' | sort | paste -sd ',' - || true)
|
|
138
|
+
echo " env: ${PROJECT_NAME}/.env.local -> ${DEST} (${VAR_COUNT} variable(s) [${VAR_NAMES}])"
|
|
139
|
+
(( ENV_COUNT++ )) || true
|
|
140
|
+
done < <(find "${EXTRACT_DIR}" -name ".env.local" -print0)
|
|
141
|
+
|
|
142
|
+
AGENT_AUTH_SRC="${EXTRACT_DIR}/agent-auth"
|
|
143
|
+
echo " agent-auth:"
|
|
144
|
+
for ENTRY in "${AGENT_AUTH_MAP[@]}"; do
|
|
145
|
+
ARCHIVE_NAME="${ENTRY%%:*}"
|
|
146
|
+
DEST_PATH="${ENTRY##*:}"
|
|
147
|
+
SRC_FILE="${AGENT_AUTH_SRC}/${ARCHIVE_NAME}"
|
|
148
|
+
if [[ -f "${SRC_FILE}" ]]; then
|
|
149
|
+
FILE_BYTES=$(wc -c < "${SRC_FILE}" | tr -d ' ')
|
|
150
|
+
echo " present: agent-auth/${ARCHIVE_NAME} -> ${DEST_PATH} (${FILE_BYTES} bytes)"
|
|
151
|
+
(( AGENT_PRESENT++ )) || true
|
|
152
|
+
else
|
|
153
|
+
echo " missing: agent-auth/${ARCHIVE_NAME}"
|
|
154
|
+
(( AGENT_MISSING++ )) || true
|
|
155
|
+
fi
|
|
156
|
+
done
|
|
157
|
+
|
|
158
|
+
echo ""
|
|
159
|
+
echo "List summary: ${ENV_COUNT} .env.local file(s), ${AGENT_PRESENT} agent-auth file(s) present, ${AGENT_MISSING} agent-auth file(s) missing."
|
|
160
|
+
echo "No files were written and no secret values were printed."
|
|
161
|
+
exit 0
|
|
162
|
+
fi
|
|
163
|
+
|
|
122
164
|
# ── restore each .env.local ───────────────────────────────────────────────────
|
|
123
165
|
RESTORED=0
|
|
124
166
|
SKIPPED=0
|
|
@@ -28,7 +28,8 @@ 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
|
+
- **Identity plane:** `youmd sync --daemon` (Convex ↔ local profile, memories, preferences). Automated via `com.youmd.identity-sync` daemon. Daemon mode refreshes local files/skills and skips unsafe lossy pushes instead of forcing over richer server data.
|
|
32
|
+
- **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
33
|
- **Env-vault plane:** `cli/scripts/env-vault/restore.sh` for secrets (manual, invoked on new machine); also available as `youmd env restore <vault>`.
|
|
33
34
|
|
|
34
35
|
---
|
|
@@ -38,10 +39,11 @@ Cross-machine sync toolkit for Houston Golden's agent skill/stack setup.
|
|
|
38
39
|
```
|
|
39
40
|
cli/scripts/skillstack-sync/
|
|
40
41
|
├── sync.sh Core syncer (bash 3.2 compatible)
|
|
41
|
-
├── install-daemons.sh Installs
|
|
42
|
+
├── install-daemons.sh Installs all resident LaunchAgents
|
|
42
43
|
├── bootstrap-new-mac.sh New machine setup script
|
|
43
44
|
├── 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
|
|
45
|
+
├── com.youmd.identity-sync.plist LaunchAgent: runs `youmd sync --daemon` every 5 min
|
|
46
|
+
├── com.youmd.context-sync.plist LaunchAgent: runs `youmd stack context-sync` every 15 min
|
|
45
47
|
└── README.md This file
|
|
46
48
|
```
|
|
47
49
|
|
|
@@ -90,7 +92,7 @@ GIT_USER_EMAIL="houston@bamf.ai" # commit email (default)
|
|
|
90
92
|
The preferred way is via the CLI:
|
|
91
93
|
|
|
92
94
|
```bash
|
|
93
|
-
youmd stack daemon install # installs
|
|
95
|
+
youmd stack daemon install # installs all resident LaunchAgents
|
|
94
96
|
youmd stack daemon status # check loaded/not-loaded
|
|
95
97
|
youmd stack daemon uninstall # remove plists from ~/Library/LaunchAgents/
|
|
96
98
|
```
|
|
@@ -101,9 +103,10 @@ Or run the raw script directly:
|
|
|
101
103
|
bash cli/scripts/skillstack-sync/install-daemons.sh
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
Installs
|
|
106
|
+
Installs three LaunchAgents:
|
|
105
107
|
- `com.youmd.skillstack-sync` → runs `youmd stack sync`
|
|
106
|
-
- `com.youmd.identity-sync` → runs `youmd sync`
|
|
108
|
+
- `com.youmd.identity-sync` → runs `youmd sync --daemon`
|
|
109
|
+
- `com.youmd.context-sync` → runs `youmd stack context-sync`
|
|
107
110
|
|
|
108
111
|
Check status:
|
|
109
112
|
```bash
|
|
@@ -111,6 +114,7 @@ youmd stack daemon status
|
|
|
111
114
|
# or directly:
|
|
112
115
|
launchctl list com.youmd.skillstack-sync
|
|
113
116
|
launchctl list com.youmd.identity-sync
|
|
117
|
+
launchctl list com.youmd.context-sync
|
|
114
118
|
```
|
|
115
119
|
|
|
116
120
|
Check logs:
|
|
@@ -118,6 +122,7 @@ Check logs:
|
|
|
118
122
|
tail -f ~/.youmd/logs/skillstack-sync.log
|
|
119
123
|
tail -f ~/.youmd/logs/skillstack-sync.out.log
|
|
120
124
|
tail -f ~/.youmd/logs/identity-sync.out.log
|
|
125
|
+
tail -f ~/.youmd/logs/context-sync.log
|
|
121
126
|
```
|
|
122
127
|
|
|
123
128
|
### Uninstall daemons
|
|
@@ -130,8 +135,10 @@ Or manually:
|
|
|
130
135
|
```bash
|
|
131
136
|
launchctl unload ~/Library/LaunchAgents/com.youmd.skillstack-sync.plist
|
|
132
137
|
launchctl unload ~/Library/LaunchAgents/com.youmd.identity-sync.plist
|
|
138
|
+
launchctl unload ~/Library/LaunchAgents/com.youmd.context-sync.plist
|
|
133
139
|
rm ~/Library/LaunchAgents/com.youmd.skillstack-sync.plist
|
|
134
140
|
rm ~/Library/LaunchAgents/com.youmd.identity-sync.plist
|
|
141
|
+
rm ~/Library/LaunchAgents/com.youmd.context-sync.plist
|
|
135
142
|
```
|
|
136
143
|
|
|
137
144
|
---
|
|
@@ -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>
|
|
@@ -146,6 +146,49 @@ existing_context_paths() {
|
|
|
146
146
|
echo "${found}"
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
path_is_context() {
|
|
150
|
+
local changed="$1"
|
|
151
|
+
local p
|
|
152
|
+
for p in ${CONTEXT_PATHSPECS}; do
|
|
153
|
+
if [ "${changed}" = "${p}" ]; then
|
|
154
|
+
return 0
|
|
155
|
+
fi
|
|
156
|
+
case "${changed}" in
|
|
157
|
+
"${p}/"*) return 0 ;;
|
|
158
|
+
esac
|
|
159
|
+
done
|
|
160
|
+
return 1
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
remote_has_non_context_changes() {
|
|
164
|
+
local repo="$1" repo_name="$2" upstream="$3"
|
|
165
|
+
local changed non_context line
|
|
166
|
+
changed="$(git -C "${repo}" diff --name-only "HEAD..${upstream}" 2>/dev/null || true)"
|
|
167
|
+
if [ -z "${changed}" ]; then
|
|
168
|
+
return 1
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
non_context=""
|
|
172
|
+
while IFS= read -r line; do
|
|
173
|
+
[ -z "${line}" ] && continue
|
|
174
|
+
if ! path_is_context "${line}"; then
|
|
175
|
+
if [ -z "${non_context}" ]; then
|
|
176
|
+
non_context="${line}"
|
|
177
|
+
else
|
|
178
|
+
non_context="${non_context}, ${line}"
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
done <<EOF
|
|
182
|
+
${changed}
|
|
183
|
+
EOF
|
|
184
|
+
|
|
185
|
+
if [ -n "${non_context}" ]; then
|
|
186
|
+
log_warn "${repo_name}: upstream has non-context changes (${non_context}). Skipping pull/push so context-sync never merges application code."
|
|
187
|
+
return 0
|
|
188
|
+
fi
|
|
189
|
+
return 1
|
|
190
|
+
}
|
|
191
|
+
|
|
149
192
|
# ---------------------------------------------------------------------------
|
|
150
193
|
# SYNC ONE REPO
|
|
151
194
|
# Returns 0 on success, 1 on non-fatal failure.
|
|
@@ -263,8 +306,33 @@ sync_context_repo() {
|
|
|
263
306
|
|
|
264
307
|
# ---- Pull (merge, no rebase) ---------------------------------------------
|
|
265
308
|
if is_dry; then
|
|
266
|
-
log_dry "Would
|
|
309
|
+
log_dry "Would fetch upstream and pull only if remote changes are limited to context paths in ${repo_name}"
|
|
267
310
|
else
|
|
311
|
+
local upstream
|
|
312
|
+
upstream="$(git -C "${repo}" rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true)"
|
|
313
|
+
if [ -z "${upstream}" ]; then
|
|
314
|
+
log_warn "Skipping pull/push for ${repo_name}: no upstream branch configured."
|
|
315
|
+
return 0
|
|
316
|
+
fi
|
|
317
|
+
|
|
318
|
+
local fetch_log
|
|
319
|
+
fetch_log="$(mktemp -t context_sync_fetch)"
|
|
320
|
+
local fetch_ok=0
|
|
321
|
+
git -C "${repo}" fetch --quiet >"${fetch_log}" 2>&1 || fetch_ok=$?
|
|
322
|
+
if [ "${fetch_ok}" -ne 0 ]; then
|
|
323
|
+
while IFS= read -r line; do
|
|
324
|
+
log "fetch|${repo_name}: ${line}"
|
|
325
|
+
done < "${fetch_log}"
|
|
326
|
+
rm -f "${fetch_log}"
|
|
327
|
+
log_error "Fetch FAILED for ${repo_name}. Skipping pull/push."
|
|
328
|
+
return 1
|
|
329
|
+
fi
|
|
330
|
+
rm -f "${fetch_log}"
|
|
331
|
+
|
|
332
|
+
if remote_has_non_context_changes "${repo}" "${repo_name}" "${upstream}"; then
|
|
333
|
+
return 0
|
|
334
|
+
fi
|
|
335
|
+
|
|
268
336
|
local pull_log
|
|
269
337
|
# BSD mktemp: no -p, use /tmp explicitly
|
|
270
338
|
pull_log="$(mktemp -t context_sync_pull)"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# install-daemons.sh — install
|
|
2
|
+
# install-daemons.sh — install resident You.md sync LaunchAgents
|
|
3
3
|
#
|
|
4
4
|
# Idempotent: safe to re-run. Unloads before reloading.
|
|
5
5
|
# Does NOT need sudo — LaunchAgents run as the current user.
|
|
@@ -12,7 +12,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
12
12
|
LAUNCH_AGENTS_DIR="${HOME}/Library/LaunchAgents"
|
|
13
13
|
LOG_DIR="${HOME}/.youmd/logs"
|
|
14
14
|
|
|
15
|
-
PLISTS="com.youmd.skillstack-sync com.youmd.identity-sync"
|
|
15
|
+
PLISTS="com.youmd.skillstack-sync com.youmd.identity-sync com.youmd.context-sync"
|
|
16
16
|
|
|
17
17
|
echo "==> Creating log directory: ${LOG_DIR}"
|
|
18
18
|
mkdir -p "${LOG_DIR}"
|
|
@@ -55,7 +55,7 @@ done
|
|
|
55
55
|
|
|
56
56
|
echo ""
|
|
57
57
|
echo "================================================================"
|
|
58
|
-
echo "
|
|
58
|
+
echo "Resident You.md daemons installed and running."
|
|
59
59
|
echo ""
|
|
60
60
|
echo "Log files:"
|
|
61
61
|
echo " ${LOG_DIR}/skillstack-sync.log (combined sync log)"
|
|
@@ -63,10 +63,14 @@ echo " ${LOG_DIR}/skillstack-sync.out.log (daemon stdout)"
|
|
|
63
63
|
echo " ${LOG_DIR}/skillstack-sync.err.log (daemon stderr)"
|
|
64
64
|
echo " ${LOG_DIR}/identity-sync.out.log (youmd sync stdout)"
|
|
65
65
|
echo " ${LOG_DIR}/identity-sync.err.log (youmd sync stderr)"
|
|
66
|
+
echo " ${LOG_DIR}/context-sync.log (combined project-context sync log)"
|
|
67
|
+
echo " ${LOG_DIR}/context-sync.out.log (daemon stdout)"
|
|
68
|
+
echo " ${LOG_DIR}/context-sync.err.log (daemon stderr)"
|
|
66
69
|
echo ""
|
|
67
70
|
echo "Check daemon status:"
|
|
68
71
|
echo " launchctl list com.youmd.skillstack-sync"
|
|
69
72
|
echo " launchctl list com.youmd.identity-sync"
|
|
73
|
+
echo " launchctl list com.youmd.context-sync"
|
|
70
74
|
echo ""
|
|
71
75
|
echo "To uninstall:"
|
|
72
76
|
for label in ${PLISTS}; do
|