@keepur/hive 0.1.10 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env bash
2
+ # Shell smoke test for deploy.sh helpers. Not unit tests in the TS sense —
3
+ # this is a scratch-dir exercise of fetch_engine / swap_engine / rollback_engine.
4
+ # Run manually: ./service/deploy.test.sh
5
+ # Exit 0 on success, non-zero on failure.
6
+
7
+ set -euo pipefail
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ TESTROOT=$(mktemp -d -t hive-deploy-test.XXXXXX)
11
+ trap 'rm -rf "$TESTROOT"' EXIT
12
+
13
+ # Shim npm pack: emit a valid tarball with package.json + pkg/server.min.js + seeds/
14
+ # structured to match the real @keepur/hive layout.
15
+ SHIM_DIR="$TESTROOT/bin-shim"
16
+ mkdir -p "$SHIM_DIR"
17
+ cat > "$SHIM_DIR/npm" <<'NPMEOF'
18
+ #!/usr/bin/env bash
19
+ # Minimal shim — handles `npm pack @keepur/hive@<version>` and `npm view`.
20
+ # Builds the pretend tarball via a `package/` staging dir so the layout works
21
+ # on both GNU tar and macOS bsdtar (no --transform dependency).
22
+ case "$1" in
23
+ pack)
24
+ # $PWD at shim entry is the caller's chosen packdir (fetch_engine does `cd "$packdir"`).
25
+ outdir="$PWD"
26
+ stage=$(mktemp -d)
27
+ mkdir -p "$stage/package/pkg" "$stage/package/seeds" "$stage/package/templates" "$stage/package/scripts" "$stage/package/install" "$stage/package/service"
28
+ echo "// fake server bundle" > "$stage/package/pkg/server.min.js"
29
+ echo "// fake cli bundle" > "$stage/package/pkg/cli.min.js"
30
+ echo "#!/usr/bin/env bash" > "$stage/package/scripts/honeypot"
31
+ chmod +x "$stage/package/scripts/honeypot"
32
+ echo "#!/usr/bin/env bash" > "$stage/package/install/migrate-0.2.sh"
33
+ echo "#!/usr/bin/env bash" > "$stage/package/service/deploy.sh"
34
+ # Version comes from @keepur/hive@<version> arg. `npm pack latest` should yield a real version.
35
+ version="${2#*@keepur/hive@}"
36
+ [[ "$version" == "@keepur/hive" || -z "$version" || "$version" == "latest" ]] && version="0.2.0"
37
+ echo '{"name":"@keepur/hive","version":"'"$version"'"}' > "$stage/package/package.json"
38
+ tarball="keepur-hive-${version}.tgz"
39
+ (cd "$stage" && tar -czf "$outdir/$tarball" package)
40
+ rm -rf "$stage"
41
+ echo "$tarball"
42
+ ;;
43
+ view)
44
+ echo "0.2.0"
45
+ ;;
46
+ *)
47
+ exec /usr/bin/env npm "$@"
48
+ ;;
49
+ esac
50
+ NPMEOF
51
+ chmod +x "$SHIM_DIR/npm"
52
+
53
+ export PATH="$SHIM_DIR:$PATH"
54
+ export BUILD_DIR="$TESTROOT/build" # fallback path
55
+ export DEPLOY_DIR="$TESTROOT/deploy"
56
+
57
+ mkdir -p "$BUILD_DIR/pkg" "$BUILD_DIR/seeds" "$BUILD_DIR/templates" "$BUILD_DIR/scripts" "$BUILD_DIR/install" "$BUILD_DIR/service"
58
+ echo "// fallback server" > "$BUILD_DIR/pkg/server.min.js"
59
+ echo "#!/usr/bin/env bash" > "$BUILD_DIR/install/migrate-0.2.sh"
60
+ echo "#!/usr/bin/env bash" > "$BUILD_DIR/service/deploy.sh"
61
+ echo '{"name":"@keepur/hive","version":"0.2.0-dev"}' > "$BUILD_DIR/package.json"
62
+
63
+ # Source the helpers from deploy.sh (extract the fetch/swap/rollback block).
64
+ # Rather than run the whole script (which does its own init), we extract the
65
+ # function bodies via sed and source them in isolation. The inner `/!p` drops
66
+ # the closing delimiter line so we don't capture the `if $ROLLBACK; then` line
67
+ # (which would trip set -u on undefined ROLLBACK when sourced).
68
+ sed -n '/^# --- Engine fetch\/swap\/rollback/,/^# --- Short-circuit:/{/^# --- Short-circuit:/!p;}' \
69
+ "$SCRIPT_DIR/deploy.sh" > "$TESTROOT/helpers.sh"
70
+ # Helper bodies reference $DRY_RUN (added so --dry-run skips the destructive
71
+ # ops); set it false here so the helpers actually execute under set -u.
72
+ DRY_RUN=false
73
+ # shellcheck source=/dev/null
74
+ source "$TESTROOT/helpers.sh"
75
+
76
+ # --- Test 1: fetch_engine via npm pack ---
77
+ echo "test 1: fetch_engine @latest via npm pack"
78
+ mkdir -p "$DEPLOY_DIR"
79
+ fetch_engine "$DEPLOY_DIR" "latest"
80
+ [[ -f "$DEPLOY_DIR/.hive.next/pkg/server.min.js" ]] || { echo "FAIL: pkg/server.min.js missing"; exit 1; }
81
+ [[ -f "$DEPLOY_DIR/.hive.next/package.json" ]] || { echo "FAIL: package.json missing"; exit 1; }
82
+
83
+ # --- Test 2: swap_engine rotates correctly ---
84
+ echo "test 2: swap_engine rotates .hive/.hive.prev"
85
+ swap_engine "$DEPLOY_DIR"
86
+ [[ -d "$DEPLOY_DIR/.hive" ]] || { echo "FAIL: .hive missing after swap"; exit 1; }
87
+ [[ ! -d "$DEPLOY_DIR/.hive.next" ]] || { echo "FAIL: .hive.next still present"; exit 1; }
88
+ # First deploy: no .hive.prev because there was no prior .hive
89
+ [[ ! -d "$DEPLOY_DIR/.hive.prev" ]] || { echo "FAIL: .hive.prev should not exist on first deploy"; exit 1; }
90
+
91
+ # --- Test 3: second deploy creates .hive.prev ---
92
+ echo "test 3: second deploy creates .hive.prev"
93
+ fetch_engine "$DEPLOY_DIR" "latest"
94
+ swap_engine "$DEPLOY_DIR"
95
+ [[ -d "$DEPLOY_DIR/.hive" ]] || { echo "FAIL: .hive missing"; exit 1; }
96
+ [[ -d "$DEPLOY_DIR/.hive.prev" ]] || { echo "FAIL: .hive.prev should now exist"; exit 1; }
97
+
98
+ # --- Test 4: rollback_engine swaps .hive ↔ .hive.prev ---
99
+ echo "test 4: rollback_engine"
100
+ echo "marker-new" > "$DEPLOY_DIR/.hive/marker"
101
+ echo "marker-prev" > "$DEPLOY_DIR/.hive.prev/marker"
102
+ rollback_engine "$DEPLOY_DIR"
103
+ [[ "$(cat "$DEPLOY_DIR/.hive/marker")" == "marker-prev" ]] || { echo "FAIL: rollback did not restore prev"; exit 1; }
104
+ [[ "$(cat "$DEPLOY_DIR/.hive.broken/marker")" == "marker-new" ]] || { echo "FAIL: failed engine not preserved as .hive.broken"; exit 1; }
105
+ [[ ! -d "$DEPLOY_DIR/.hive.prev" ]] || { echo "FAIL: .hive.prev should be consumed by rollback"; exit 1; }
106
+
107
+ # --- Test 5: rollback fails cleanly when .hive.prev missing ---
108
+ echo "test 5: rollback without .hive.prev errors"
109
+ rm -rf "$DEPLOY_DIR/.hive.prev"
110
+ if rollback_engine "$DEPLOY_DIR" 2>/dev/null; then
111
+ echo "FAIL: rollback_engine should have errored"
112
+ exit 1
113
+ fi
114
+
115
+ # --- Test 6: next successful deploy clears .hive.broken ---
116
+ echo "test 6: swap clears .hive.broken"
117
+ fetch_engine "$DEPLOY_DIR" "latest"
118
+ swap_engine "$DEPLOY_DIR"
119
+ [[ ! -d "$DEPLOY_DIR/.hive.broken" ]] || { echo "FAIL: .hive.broken should be rotated out by successful swap"; exit 1; }
120
+
121
+ # --- Test 7: fallback rsync path (when npm view returns empty for a tag) ---
122
+ echo "test 7: fallback rsync path"
123
+ # Replace the shim so `npm view @keepur/hive@<tag>` returns nothing (tag unknown),
124
+ # forcing fetch_engine's fallback branch. Note: the "latest" branch of fetch_engine
125
+ # is hardwired to always take the npm-pack path, so we pass a concrete fake tag
126
+ # the shim will reject on `view`.
127
+ cat > "$SHIM_DIR/npm" <<'NPMEOF'
128
+ #!/usr/bin/env bash
129
+ case "$1" in
130
+ view) exit 0 ;; # empty stdout → fetch_engine falls through
131
+ pack) echo "ERROR: shim rejects pack"; exit 1 ;;
132
+ *) exit 0 ;;
133
+ esac
134
+ NPMEOF
135
+ chmod +x "$SHIM_DIR/npm"
136
+ rm -rf "$DEPLOY_DIR"
137
+ mkdir -p "$DEPLOY_DIR"
138
+ # Now fetch_engine should skip npm pack and use $BUILD_DIR
139
+ if ! fetch_engine "$DEPLOY_DIR" "0.9.9-nonexistent" 2>&1 | grep -q "falling back"; then
140
+ echo "FAIL: fallback path not taken when npm view returns empty"
141
+ exit 1
142
+ fi
143
+ [[ -f "$DEPLOY_DIR/.hive.next/pkg/server.min.js" ]] || { echo "FAIL: fallback did not populate pkg/server.min.js"; exit 1; }
144
+ # service/deploy.sh must reach .hive.next/ — hive update/rollback both shell out
145
+ # to it from .hive/service/, so a missing rsync here would brick both commands.
146
+ [[ -f "$DEPLOY_DIR/.hive.next/service/deploy.sh" ]] || { echo "FAIL: fallback did not populate service/deploy.sh"; exit 1; }
147
+ [[ -f "$DEPLOY_DIR/.hive.next/install/migrate-0.2.sh" ]] || { echo "FAIL: fallback did not populate install/migrate-0.2.sh"; exit 1; }
148
+
149
+ # --- Test 8: --dry-run skips destructive ops in helpers ---
150
+ echo "test 8: dry-run helpers don't mutate disk"
151
+ rm -rf "$DEPLOY_DIR"
152
+ mkdir -p "$DEPLOY_DIR"
153
+ DRY_RUN=true
154
+ fetch_engine "$DEPLOY_DIR" "latest" >/dev/null
155
+ [[ ! -d "$DEPLOY_DIR/.hive.next" ]] || { echo "FAIL: dry-run fetch_engine created .hive.next"; exit 1; }
156
+ install_engine_deps "$DEPLOY_DIR" >/dev/null
157
+ swap_engine "$DEPLOY_DIR" >/dev/null
158
+ [[ ! -d "$DEPLOY_DIR/.hive" ]] || { echo "FAIL: dry-run swap_engine created .hive"; exit 1; }
159
+ # rollback in dry-run with no .hive.prev should report failure but not touch disk
160
+ if rollback_engine "$DEPLOY_DIR" >/dev/null 2>&1; then
161
+ echo "FAIL: dry-run rollback_engine should have returned 1 (no .hive.prev)"
162
+ exit 1
163
+ fi
164
+ [[ ! -d "$DEPLOY_DIR/.hive.broken" ]] || { echo "FAIL: dry-run rollback created .hive.broken"; exit 1; }
165
+ DRY_RUN=false
166
+
167
+ # --- Test 9: install_engine_deps runs npm install inside .hive.next ---
168
+ echo "test 9: install_engine_deps runs npm install in .hive.next/"
169
+ # Restore full shim so npm pack works
170
+ cat > "$SHIM_DIR/npm" <<'NPMEOF'
171
+ #!/usr/bin/env bash
172
+ outdir="$PWD"
173
+ case "$1" in
174
+ pack)
175
+ stage=$(mktemp -d)
176
+ mkdir -p "$stage/package/pkg" "$stage/package/seeds" "$stage/package/templates" "$stage/package/scripts"
177
+ echo "// fake server bundle" > "$stage/package/pkg/server.min.js"
178
+ echo '{"name":"@keepur/hive","version":"0.2.0"}' > "$stage/package/package.json"
179
+ tarball="keepur-hive-0.2.0.tgz"
180
+ (cd "$stage" && tar -czf "$outdir/$tarball" package)
181
+ rm -rf "$stage"
182
+ echo "$tarball"
183
+ ;;
184
+ view) echo "0.2.0" ;;
185
+ install)
186
+ # Record that npm install ran in the scratch dir so the test can verify it
187
+ touch "$PWD/.install-ran"
188
+ ;;
189
+ *) exit 0 ;;
190
+ esac
191
+ NPMEOF
192
+ chmod +x "$SHIM_DIR/npm"
193
+ rm -rf "$DEPLOY_DIR"
194
+ mkdir -p "$DEPLOY_DIR"
195
+ fetch_engine "$DEPLOY_DIR" "latest" >/dev/null
196
+ install_engine_deps "$DEPLOY_DIR" >/dev/null
197
+ [[ -f "$DEPLOY_DIR/.hive.next/.install-ran" ]] || { echo "FAIL: install_engine_deps didn't run npm install in .hive.next/"; exit 1; }
198
+
199
+ # --- Test 10: install_engine_deps errors when package.json missing ---
200
+ echo "test 10: install_engine_deps errors when .hive.next/package.json missing"
201
+ rm -rf "$DEPLOY_DIR"
202
+ mkdir -p "$DEPLOY_DIR/.hive.next" # empty dir, no package.json
203
+ if install_engine_deps "$DEPLOY_DIR" >/dev/null 2>&1; then
204
+ echo "FAIL: install_engine_deps should have errored without package.json"
205
+ exit 1
206
+ fi
207
+
208
+ echo "all tests passed."
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Install Hive as a LaunchAgent (user scope).
5
+ # Generates plists, symlinks them into ~/Library/LaunchAgents, and bootstraps.
6
+ #
7
+ # Set HIVE_DEPLOY_DIR to override the working directory (default: ~/services/<instance-id>)
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ HIVE_ROOT="$(dirname "$SCRIPT_DIR")"
11
+
12
+ # Read instance ID from hive.yaml (falls back to "hive")
13
+ INSTANCE_ID=$(grep '^\s*id:' "$HIVE_ROOT/hive.yaml" 2>/dev/null | head -1 | awk '{print $2}')
14
+ [[ -z "$INSTANCE_ID" ]] && INSTANCE_ID="hive"
15
+
16
+ DEPLOY_DIR="${HIVE_DEPLOY_DIR:-$HOME/services/$INSTANCE_ID}"
17
+ LAUNCH_AGENTS_DIR="$HOME/Library/LaunchAgents"
18
+
19
+ LABEL="com.hive.${INSTANCE_ID}.agent"
20
+ LABEL_LOGS="com.hive.${INSTANCE_ID}.rotate-logs"
21
+ LABEL_DEPLOY="com.hive.${INSTANCE_ID}.deploy-check"
22
+
23
+ echo "Installing Hive LaunchAgents..."
24
+ echo " Deploy dir: $DEPLOY_DIR"
25
+
26
+ # Generate plists pointing to the deploy directory
27
+ cd "$HIVE_ROOT"
28
+ HIVE_DEPLOY_DIR="$DEPLOY_DIR" npx tsx setup/generate-plist.ts
29
+
30
+ # Ensure LaunchAgents directory exists
31
+ mkdir -p "$LAUNCH_AGENTS_DIR"
32
+
33
+ # Unload existing services if running (ignore errors if not loaded)
34
+ for lbl in "$LABEL" "$LABEL_LOGS" "$LABEL_DEPLOY"; do
35
+ launchctl bootout "gui/$(id -u)/$lbl" 2>/dev/null || true
36
+ done
37
+
38
+ # Symlink plists into LaunchAgents
39
+ ln -sf "$HIVE_ROOT/service/$LABEL.plist" "$LAUNCH_AGENTS_DIR/$LABEL.plist"
40
+ ln -sf "$HIVE_ROOT/service/$LABEL_LOGS.plist" "$LAUNCH_AGENTS_DIR/$LABEL_LOGS.plist"
41
+ ln -sf "$HIVE_ROOT/service/$LABEL_DEPLOY.plist" "$LAUNCH_AGENTS_DIR/$LABEL_DEPLOY.plist"
42
+
43
+ # Ensure logs directory exists
44
+ mkdir -p "$DEPLOY_DIR/logs"
45
+
46
+ # Make rotate script executable
47
+ chmod +x "$HIVE_ROOT/service/rotate-logs.sh"
48
+ chmod +x "$HIVE_ROOT/service/deploy-check.sh"
49
+
50
+ # Bootstrap (load and start)
51
+ launchctl bootstrap "gui/$(id -u)" "$LAUNCH_AGENTS_DIR/$LABEL.plist"
52
+ launchctl bootstrap "gui/$(id -u)" "$LAUNCH_AGENTS_DIR/$LABEL_LOGS.plist"
53
+ launchctl bootstrap "gui/$(id -u)" "$LAUNCH_AGENTS_DIR/$LABEL_DEPLOY.plist"
54
+
55
+ echo ""
56
+ echo "✓ Hive service installed (LaunchAgent, user scope)"
57
+ echo " Label: $LABEL"
58
+ echo " Working dir: $DEPLOY_DIR"
59
+ echo " Logs: $DEPLOY_DIR/logs/"
60
+ echo ""
61
+ echo "Manage with:"
62
+ echo " launchctl kickstart -k gui/$(id -u)/$LABEL # restart"
63
+ echo " launchctl bootout gui/$(id -u)/$LABEL # stop"
64
+ echo " launchctl print gui/$(id -u)/$LABEL # status"
@@ -0,0 +1,11 @@
1
+ # Hive instance definitions — one per line
2
+ # Fields: INSTANCE_ID | HIVE_CONFIG | (unused) | LAUNCHAGENT_LABEL | LOGS_DIR | PORTS (space-separated) | ENGINE_TAG
3
+ #
4
+ # HIVE_CONFIG is relative to DEPLOY_DIR
5
+ # Agents are stored in MongoDB (agent_definitions collection), not on disk
6
+ # PORTS are checked/killed on deploy restart
7
+ # ENGINE_TAG is the npm version tag to deploy for this instance. Accepts `v0.2.0` or `0.2.0`
8
+ # (leading `v` stripped before npm calls). Omit to default to the `latest` dist-tag.
9
+
10
+ dodi|hive.yaml|-|com.hive.agent|logs|3100 3200|v0.2.0
11
+ personal|hive-personal.yaml|-|com.hive.personal.agent|logs-personal|3400 3403|v0.2.0
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ KEEP_DAYS=3
5
+ TIMESTAMP=$(date +%Y-%m-%dT%H-%M-%S)
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ HIVE_ROOT="$(dirname "$SCRIPT_DIR")"
9
+ INSTANCES_CONF="$SCRIPT_DIR/instances.conf"
10
+
11
+ # --- MongoDB ---
12
+ if command -v mongosh &>/dev/null; then
13
+ MONGO_LOG_DIR="/opt/homebrew/var/log/mongodb"
14
+ mongosh --quiet --eval 'db.adminCommand({logRotate: 1})' >/dev/null 2>&1 || true
15
+ find "$MONGO_LOG_DIR" -name "mongo.log.*" -mtime +${KEEP_DAYS} -delete 2>/dev/null || true
16
+ fi
17
+
18
+ # --- Per-instance logs ---
19
+ while IFS='|' read -r id config agents_path label logs_dir ports; do
20
+ [[ "$id" =~ ^[[:space:]]*# ]] && continue
21
+ [[ -z "$id" ]] && continue
22
+ logs_dir=$(echo "$logs_dir" | xargs)
23
+
24
+ LOG_DIR="$HIVE_ROOT/$logs_dir"
25
+ [[ -d "$LOG_DIR" ]] || continue
26
+
27
+ for logfile in hive.log hive.err; do
28
+ src="$LOG_DIR/$logfile"
29
+ if [ -s "$src" ]; then
30
+ cp "$src" "$LOG_DIR/${logfile}.${TIMESTAMP}"
31
+ : > "$src"
32
+ fi
33
+ done
34
+ find "$LOG_DIR" -name "hive.*.2*" -mtime +${KEEP_DAYS} -delete 2>/dev/null || true
35
+ done < "$INSTANCES_CONF"
36
+
37
+ # --- Deploy checker ---
38
+ DEPLOY_LOG="$HIVE_ROOT/logs/deploy-check.log"
39
+ if [ -s "$DEPLOY_LOG" ]; then
40
+ cp "$DEPLOY_LOG" "$HIVE_ROOT/logs/deploy-check.log.${TIMESTAMP}"
41
+ : > "$DEPLOY_LOG"
42
+ fi
43
+ find "$HIVE_ROOT/logs" -name "deploy-check.*.2*" -mtime +${KEEP_DAYS} -delete 2>/dev/null || true