mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-03 23:37:53 +01:00
Bins, careful/freeze hooks, setup, upgrade migrations, browse/src, design, ios-qa daemon, lib and scripts resolve the state root through bin/gstack-state-root.sh (bash) or lib/state-root.ts (TS). Bins source the twin and stop with a reinstall message when it is missing; hooks source it and never spawn gstack-paths. browse/src/config.ts and lib/cso/state.ts delegate to resolveStateRoot. Analytics writers and readers move together so the usage log stays one file. gstack-uninstall deletes state only at ~/.gstack, refuses (exit 2) when it resolves to /, $HOME or an ancestor, the checkout or the git root, and leaves any other resolved root in place with the removal command. Fixtures that copy single bins now copy the twin.
67 lines
2.7 KiB
Bash
Executable File
67 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gstack-brain-enqueue — write a path record into the GBrain sync spool.
|
|
#
|
|
# Usage:
|
|
# gstack-brain-enqueue <file-path>
|
|
#
|
|
# Called by writer scripts (gstack-learnings-log, gstack-timeline-log, etc.)
|
|
# after their local write. Fire-and-forget; failures are silent (never blocks
|
|
# the writer). The spool is drained by `gstack-brain-sync --once` invoked from
|
|
# the preamble at skill START and END boundaries.
|
|
#
|
|
# No-op when:
|
|
# - artifacts_sync_mode is off (the default)
|
|
# - ~/.gstack/.git doesn't exist (feature not initialized)
|
|
# - <file-path> matches a line in ~/.gstack/.brain-skip.txt
|
|
#
|
|
# Env:
|
|
# GSTACK_HOME — override ~/.gstack state directory (aligns with writers).
|
|
# Tests use GSTACK_HOME=/tmp/test-$$ for isolation.
|
|
#
|
|
# Concurrency: maildir-style spool — one FILE per record under
|
|
# .brain-queue.d/, created via tmp-file + atomic rename. Writer and drainer
|
|
# never share an inode, so there is no append/rewrite race by construction
|
|
# (the legacy single-file .brain-queue.jsonl append could race the drain's
|
|
# rewrite). Filenames are <epoch>-<pid>-<uniq>.json, so a sorted listing is
|
|
# chronological.
|
|
|
|
# No `-e` — writer shims rely on this never failing loudly.
|
|
set -uo pipefail
|
|
|
|
FILE="${1:-}"
|
|
[ -z "$FILE" ] && exit 0
|
|
|
|
. "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; }
|
|
gstack_state_root_select
|
|
GSTACK_HOME="$_gstack_sr_root"
|
|
SPOOL="$GSTACK_HOME/.brain-queue.d"
|
|
SKIP_FILE="$GSTACK_HOME/.brain-skip.txt"
|
|
|
|
# Fast exits: no git repo, no sync.
|
|
[ ! -d "$GSTACK_HOME/.git" ] && exit 0
|
|
|
|
# Check sync mode. off → silent no-op.
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
|
|
MODE=$("$SCRIPT_DIR/gstack-config" get artifacts_sync_mode 2>/dev/null || echo off)
|
|
[ "$MODE" = "off" ] && exit 0
|
|
|
|
# User-maintained skip list (for secret-scan false positives).
|
|
if [ -f "$SKIP_FILE" ]; then
|
|
if grep -Fxq "$FILE" "$SKIP_FILE" 2>/dev/null; then
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# JSON-escape the file path (backslash + quotes only; paths shouldn't have other specials).
|
|
ESC_FILE=$(printf '%s' "$FILE" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "")
|
|
|
|
# One spool file per record: tmp write + atomic rename. Any failure exits 0
|
|
# silently (fire-and-forget contract), cleaning up the tmp file.
|
|
mkdir -p "$SPOOL" 2>/dev/null || exit 0
|
|
TMP="$SPOOL/.tmp-$$-$RANDOM"
|
|
printf '{"file":"%s","ts":"%s"}\n' "$ESC_FILE" "$TS" > "$TMP" 2>/dev/null || { rm -f "$TMP" 2>/dev/null; exit 0; }
|
|
mv -f "$TMP" "$SPOOL/$(date +%s)-$$-$RANDOM.json" 2>/dev/null || rm -f "$TMP" 2>/dev/null
|
|
|
|
exit 0
|