create-egregore 0.19.33 → 0.20.0
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/assets/egregore-launcher.js +118 -13
- package/bin/cli.js +19 -3
- package/lib/connect-runtime.js +4 -2
- package/lib/local.js +15 -1
- package/lib/prime-runtime.js +208 -0
- package/lib/setup.js +45 -3
- package/package.json +4 -3
- package/runtime/codex/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/spec-manifest.json +3 -3
- package/runtime/codex/AGENTS.md +11 -4
- package/runtime/codex/bin/activity-data.sh +4 -8
- package/runtime/codex/bin/attendant.sh +13 -0
- package/runtime/codex/bin/autosave.sh +27 -1
- package/runtime/codex/bin/codex-render-spec.mjs +6 -0
- package/runtime/codex/bin/codex-session-start.sh +3 -1
- package/runtime/codex/bin/graph-batch.sh +25 -6
- package/runtime/codex/bin/graph-op.sh +5 -4
- package/runtime/codex/bin/graph.sh +31 -5
- package/runtime/codex/bin/ingest.py +81 -5
- package/runtime/codex/bin/lib/context.sh +26 -1
- package/runtime/codex/bin/lib/greeting.sh +4 -1
- package/runtime/codex/bin/lib/worktree-links.sh +25 -0
- package/runtime/codex/manifest.json +7 -1
- package/runtime/pi/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/spec-manifest.json +3 -3
- package/runtime/pi/.pi/APPEND_SYSTEM.md +3 -2
- package/runtime/pi/.pi/extensions/egregore.ts +17 -6
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +11 -4
- package/runtime/pi/bin/activity-data.sh +4 -8
- package/runtime/pi/bin/attendant.sh +13 -0
- package/runtime/pi/bin/autosave.sh +27 -1
- package/runtime/pi/bin/codex-render-spec.mjs +6 -0
- package/runtime/pi/bin/codex-session-start.sh +3 -1
- package/runtime/pi/bin/graph-batch.sh +25 -6
- package/runtime/pi/bin/graph-op.sh +5 -4
- package/runtime/pi/bin/graph.sh +31 -5
- package/runtime/pi/bin/ingest.py +81 -5
- package/runtime/pi/bin/lib/context.sh +26 -1
- package/runtime/pi/bin/lib/greeting.sh +4 -1
- package/runtime/pi/bin/lib/worktree-links.sh +25 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +138 -1
- package/runtime/pi/bin/pi-product-workflows.mjs +35 -7
- package/runtime/pi/manifest.json +7 -1
- package/runtime/prime/.claude/context/notification-consent.md +66 -0
- package/runtime/prime/.codex/config.toml +17 -0
- package/runtime/prime/.codex/hooks/branch-guard.js +461 -0
- package/runtime/prime/.codex/hooks/search-hint.js +67 -0
- package/runtime/prime/.codex/hooks.json +30 -0
- package/runtime/prime/.codex/skills/activity/SKILL.md +82 -0
- package/runtime/prime/.codex/skills/announce/SKILL.md +67 -0
- package/runtime/prime/.codex/skills/archive/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/branch/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/checkup/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/commit/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/contribute/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/create-skill/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dark-mode/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/prime/.codex/skills/deep-reflect/SKILL.md +109 -0
- package/runtime/prime/.codex/skills/delete-user/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/emissary/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/handoff/SKILL.md +166 -0
- package/runtime/prime/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
- package/runtime/prime/.codex/skills/harvest/SKILL.md +131 -0
- package/runtime/prime/.codex/skills/ingest/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/invite/SKILL.md +44 -0
- package/runtime/prime/.codex/skills/issue/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/me/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/meeting/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/note/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/onboarding/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/pr/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/pull/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/push/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/quest/SKILL.md +80 -0
- package/runtime/prime/.codex/skills/reflect/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/review-pr/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/save/SKILL.md +125 -0
- package/runtime/prime/.codex/skills/slack-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/summon/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/sync-repos/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telegram-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telemetry/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/test/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/prime/.codex/skills/tui-design/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/tutorial/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/update/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/view/SKILL.md +156 -0
- package/runtime/prime/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/prime/.codex/skills/visual-explain/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/wrap/SKILL.md +58 -0
- package/runtime/prime/.codex/spec-manifest.json +132 -0
- package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +393 -0
- package/runtime/prime/.prime/agent/extensions/egregore.ts +460 -0
- package/runtime/prime/.prime/agent/settings.json +4 -0
- package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +34 -0
- package/runtime/prime/.prime/agent/skills/egregore/pyproject.toml +13 -0
- package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +156 -0
- package/runtime/prime/.prime/agent/spec-manifest.json +12 -0
- package/runtime/prime/AGENTS.md +489 -0
- package/runtime/prime/bin/activity-data.sh +238 -0
- package/runtime/prime/bin/agent.sh +775 -0
- package/runtime/prime/bin/attendant.sh +707 -0
- package/runtime/prime/bin/autosave.sh +112 -0
- package/runtime/prime/bin/capture-reconcile.sh +69 -0
- package/runtime/prime/bin/capture-run.sh +341 -0
- package/runtime/prime/bin/codex-install-skills.sh +78 -0
- package/runtime/prime/bin/codex-render-spec.mjs +440 -0
- package/runtime/prime/bin/codex-session-start.sh +265 -0
- package/runtime/prime/bin/codex-skill-render.mjs +347 -0
- package/runtime/prime/bin/codex-sync-skills.sh +232 -0
- package/runtime/prime/bin/connect-refresh.sh +33 -0
- package/runtime/prime/bin/dashboard-data.sh +178 -0
- package/runtime/prime/bin/graph-batch.sh +79 -0
- package/runtime/prime/bin/graph-op.sh +1102 -0
- package/runtime/prime/bin/graph-wal.sh +229 -0
- package/runtime/prime/bin/graph.sh +223 -0
- package/runtime/prime/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/prime/bin/handoff-run.sh +671 -0
- package/runtime/prime/bin/handoff-save-egregore.sh +212 -0
- package/runtime/prime/bin/index-handoff.sh +322 -0
- package/runtime/prime/bin/ingest-graph.sh +80 -0
- package/runtime/prime/bin/ingest-surface.html +495 -0
- package/runtime/prime/bin/ingest.py +756 -0
- package/runtime/prime/bin/ingest.sh +279 -0
- package/runtime/prime/bin/ingest_graph.py +856 -0
- package/runtime/prime/bin/ingest_surface.py +544 -0
- package/runtime/prime/bin/lib/artifact-id.sh +46 -0
- package/runtime/prime/bin/lib/config.sh +116 -0
- package/runtime/prime/bin/lib/context.sh +621 -0
- package/runtime/prime/bin/lib/dashboard-artifact.sh +242 -0
- package/runtime/prime/bin/lib/ensure-develop.sh +183 -0
- package/runtime/prime/bin/lib/git-sync.sh +406 -0
- package/runtime/prime/bin/lib/greeting.sh +519 -0
- package/runtime/prime/bin/lib/hash.sh +13 -0
- package/runtime/prime/bin/lib/identity.sh +213 -0
- package/runtime/prime/bin/lib/metrics.sh +374 -0
- package/runtime/prime/bin/lib/noncode.sh +31 -0
- package/runtime/prime/bin/lib/permissions.sh +106 -0
- package/runtime/prime/bin/lib/time.sh +56 -0
- package/runtime/prime/bin/lib/worktree-links.sh +79 -0
- package/runtime/prime/bin/notify.sh +636 -0
- package/runtime/prime/bin/person.py +630 -0
- package/runtime/prime/bin/person.sh +448 -0
- package/runtime/prime/bin/pi-branch-policy.mjs +312 -0
- package/runtime/prime/bin/pi-product-workflows.mjs +394 -0
- package/runtime/prime/bin/prime-render-spec.mjs +123 -0
- package/runtime/prime/bin/prime-session-start.sh +24 -0
- package/runtime/prime/bin/publish-artifact.sh +271 -0
- package/runtime/prime/bin/publish-references.sh +144 -0
- package/runtime/prime/bin/repo-state.sh +96 -0
- package/runtime/prime/bin/search.sh +240 -0
- package/runtime/prime/bin/session-autosave.sh +209 -0
- package/runtime/prime/bin/session-log.sh +199 -0
- package/runtime/prime/bin/settings.sh +304 -0
- package/runtime/prime/bin/telemetry.sh +391 -0
- package/runtime/prime/bin/worktree-create.sh +128 -0
- package/runtime/prime/bin/worktree-remove.sh +50 -0
- package/runtime/prime/bin/worktree.sh +198 -0
- package/runtime/prime/manifest.json +178 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# git-sync.sh — Git synchronization for session-start.sh
|
|
3
|
+
#
|
|
4
|
+
# Handles all git operations during session startup:
|
|
5
|
+
# - Pull rebase configuration
|
|
6
|
+
# - Parallel fetches (origin, upstream, memory, managed repos)
|
|
7
|
+
# - Worktree orphan cleanup
|
|
8
|
+
# - Git health check
|
|
9
|
+
# - Develop branch setup + sync
|
|
10
|
+
# - Memory sync
|
|
11
|
+
# - Managed repos sync
|
|
12
|
+
#
|
|
13
|
+
# Inputs: SCRIPT_DIR, IS_WORKTREE, MAIN_PROJECT_DIR, STATE_FILE, ENV_FILE,
|
|
14
|
+
# HEALTH_GIT, BASE_BRANCH (optional — resolved here if unset),
|
|
15
|
+
# MANAGED_REPOS (not yet set — read from config here)
|
|
16
|
+
# Outputs: HEALTH_GIT, DEVELOP_SYNCED, COMMITS_AHEAD, ACTION, SAVED_BRANCH,
|
|
17
|
+
# BRANCH, MEMORY_SYNCED, REPOS_STATUS, MANAGED_REPOS, CURRENT_BRANCH,
|
|
18
|
+
# FRAMEWORK_UPDATED, FRAMEWORK_UPDATED_COUNT, FRAMEWORK_UPDATED_FILES,
|
|
19
|
+
# BASE_BRANCH, BASE_BRANCH_READY
|
|
20
|
+
|
|
21
|
+
FRAMEWORK_UPDATED="false"
|
|
22
|
+
FRAMEWORK_UPDATED_COUNT=0
|
|
23
|
+
FRAMEWORK_UPDATED_FILES=""
|
|
24
|
+
|
|
25
|
+
# The core repo's integration branch: "develop" unless egregore.json sets
|
|
26
|
+
# base_branch. session-start.sh resolves this before sourcing; resolve it here
|
|
27
|
+
# too so the lib stands alone for other callers.
|
|
28
|
+
if [ -z "${BASE_BRANCH:-}" ]; then
|
|
29
|
+
if ! BASE_BRANCH=$(_get_base_branch); then
|
|
30
|
+
HEALTH_GIT="fail"
|
|
31
|
+
return 1 2>/dev/null || exit 1
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# --- Ensure pull.rebase is set (prevents "divergent branches" errors) ---
|
|
36
|
+
git config pull.rebase true 2>/dev/null || true
|
|
37
|
+
|
|
38
|
+
# --- Fetch all remotes in parallel ---
|
|
39
|
+
# Set git transfer timeout so hangs don't block startup indefinitely.
|
|
40
|
+
export GIT_HTTP_LOW_SPEED_LIMIT=1000 # abort if <1KB/s
|
|
41
|
+
export GIT_HTTP_LOW_SPEED_TIME=10 # for 10 seconds
|
|
42
|
+
|
|
43
|
+
# Attendant fast path: the ambient daemon (bin/attendant.sh) fetches origin,
|
|
44
|
+
# memory, and managed repos every few minutes. If its warm marker is fresh,
|
|
45
|
+
# refs are already up to date — skip the network fetches and launch on local
|
|
46
|
+
# ops only. Upstream fetch (framework update check) is not covered by the
|
|
47
|
+
# attendant and stays unconditional below.
|
|
48
|
+
_REFS_FRESH="false"
|
|
49
|
+
_ATT_SLUG=$(jq -r '.slug // "egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "egregore")
|
|
50
|
+
# Key the marker by the MAIN checkout, not this directory: the attendant keys
|
|
51
|
+
# its state by MAIN_DIR, so hashing a worktree path here meant worktree
|
|
52
|
+
# sessions never matched the warm marker and always paid the full fetch round.
|
|
53
|
+
# Worktrees share refs with the main checkout (common git dir), so the skip is
|
|
54
|
+
# equally valid there. session-start.sh provides MAIN_PROJECT_DIR; standalone
|
|
55
|
+
# callers fall back to SCRIPT_DIR (identical for non-worktree checkouts).
|
|
56
|
+
_ATT_KEY="${_ATT_SLUG}-$(echo -n "${MAIN_PROJECT_DIR:-$SCRIPT_DIR}" | cksum | cut -d' ' -f1)"
|
|
57
|
+
_ATT_MARKER="${ATTENDANT_HOME:-$HOME/.egregore/attendant}/${_ATT_KEY}.warm-ts"
|
|
58
|
+
if [ -f "$_ATT_MARKER" ]; then
|
|
59
|
+
# Harden the read: an empty or garbled marker (e.g. caught mid-write) must
|
|
60
|
+
# degrade to "not fresh", never abort startup with an arithmetic error.
|
|
61
|
+
_ATT_TS=$(cat "$_ATT_MARKER" 2>/dev/null || echo 0)
|
|
62
|
+
case "$_ATT_TS" in ''|*[!0-9]*) _ATT_TS=0 ;; esac
|
|
63
|
+
_ATT_AGE=$(( $(date +%s) - _ATT_TS ))
|
|
64
|
+
# The attendant warms every ~5min and stamps the marker AFTER its fetches
|
|
65
|
+
# finish, so a healthy marker's age peaks just above 300s. A 360s threshold
|
|
66
|
+
# made the skip a coin flip — half of boots paid the full fetch round for
|
|
67
|
+
# nothing. 600s (2× the warm cycle) means refs are at most ~10min stale at
|
|
68
|
+
# launch, and the attendant converges them minutes later anyway.
|
|
69
|
+
[ "$_ATT_AGE" -ge 0 ] && [ "$_ATT_AGE" -lt 600 ] && _REFS_FRESH="true"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
[ "$_REFS_FRESH" != "true" ] && git fetch origin --quiet 2>/dev/null &
|
|
73
|
+
|
|
74
|
+
# Fetch upstream framework (for update check — non-blocking)
|
|
75
|
+
# Default: official egregore-core repo. Set upstream_url in egregore.json to override,
|
|
76
|
+
# or set it to "none" to disable (e.g., in the dev repo where this IS the source).
|
|
77
|
+
_UPSTREAM_URL=$(jq -r '.upstream_url // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
78
|
+
[ -z "$_UPSTREAM_URL" ] && _UPSTREAM_URL="https://github.com/egregore-labs/egregore.git"
|
|
79
|
+
if [ "$_UPSTREAM_URL" != "none" ]; then
|
|
80
|
+
git remote add upstream "$_UPSTREAM_URL" 2>/dev/null || true
|
|
81
|
+
git fetch upstream main --quiet 2>/dev/null &
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Sync memory in parallel (symlink or direct directory — both valid)
|
|
85
|
+
MEMORY_SYNCED="false"
|
|
86
|
+
if [ -d "$SCRIPT_DIR/memory/.git" ] && [ "$_REFS_FRESH" != "true" ]; then
|
|
87
|
+
git -C "$SCRIPT_DIR/memory" fetch origin --quiet 2>/dev/null &
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# Fetch managed repos in parallel
|
|
91
|
+
MANAGED_REPOS=$(jq -r '(.repos[]? // empty) | if type == "object" then .name else . end' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
92
|
+
if [ "$_REFS_FRESH" != "true" ]; then
|
|
93
|
+
for REPO in $MANAGED_REPOS; do
|
|
94
|
+
if [ -d "$SCRIPT_DIR/../$REPO/.git" ]; then
|
|
95
|
+
git -C "$SCRIPT_DIR/../$REPO" fetch origin --quiet 2>/dev/null &
|
|
96
|
+
fi
|
|
97
|
+
done
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Wait for all fetches
|
|
101
|
+
wait 2>/dev/null || true
|
|
102
|
+
|
|
103
|
+
# --- Auto-update framework from upstream (deferred) ---
|
|
104
|
+
# Moved AFTER setup_develop() so framework commits land on develop, not on
|
|
105
|
+
# working branches. See _apply_framework_update() below.
|
|
106
|
+
|
|
107
|
+
# _read_auto_update — resolve the auto_update flag. Correct, and FAIL CLOSED.
|
|
108
|
+
#
|
|
109
|
+
# This flag is the only thing standing between a user's checkout and a blind
|
|
110
|
+
# `git checkout upstream/main --` over every framework path, so it has to be
|
|
111
|
+
# read exactly right. It was not.
|
|
112
|
+
#
|
|
113
|
+
# The bug: `jq -r '.auto_update // true'`. jq's `//` returns its right-hand
|
|
114
|
+
# side when the left is null *or false* — so a config saying
|
|
115
|
+
# {"auto_update": false} evaluated to the string "true", and the guard
|
|
116
|
+
# `[ "$_AUTO_UPDATE" = "false" ]` could never fire. The documented opt-out
|
|
117
|
+
# has never disabled anything for anyone. Do not reintroduce `// <bool>` for
|
|
118
|
+
# a flag whose `false` is meaningful; read the raw value and map it.
|
|
119
|
+
#
|
|
120
|
+
# Second failure: jq prints nothing and exits non-zero on a missing or
|
|
121
|
+
# malformed egregore.json, and an empty string is not "false" either — so an
|
|
122
|
+
# unreadable config also read as consent. Absent key means "on" (the intended
|
|
123
|
+
# default); everything else that is not a parsed `true` means "leave the
|
|
124
|
+
# user's files alone".
|
|
125
|
+
_read_auto_update() {
|
|
126
|
+
local _config="$SCRIPT_DIR/egregore.json"
|
|
127
|
+
local _val
|
|
128
|
+
[ -f "$_config" ] || { echo "false"; return; }
|
|
129
|
+
# `| tojson`, not a bare `-r` read: under -r a *string* "true" renders as bare
|
|
130
|
+
# true, indistinguishable from boolean true, so {"auto_update": "true"} would
|
|
131
|
+
# re-authorize the overwrite — a fail-open hole in the middle of a fail-closed
|
|
132
|
+
# resolver. tojson keeps the quotes, so the true arm matches only an absent key
|
|
133
|
+
# or a real boolean.
|
|
134
|
+
_val=$(jq -r '.auto_update | tojson' "$_config" 2>/dev/null) || { echo "false"; return; }
|
|
135
|
+
case "$_val" in
|
|
136
|
+
null|true) echo "true" ;; # key absent, or explicitly enabled
|
|
137
|
+
*) echo "false" ;; # false, "false", "true", garbage, or unparseable
|
|
138
|
+
esac
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
_apply_framework_update() {
|
|
142
|
+
# Applies framework paths from upstream to the CURRENT branch, which must be
|
|
143
|
+
# the configured base branch.
|
|
144
|
+
# Disable with "auto_update": false in egregore.json.
|
|
145
|
+
# Dev repos (upstream_url: "none") skip this entirely.
|
|
146
|
+
#
|
|
147
|
+
# The flag is read HERE, not at source time: callers reach this function
|
|
148
|
+
# after setup_develop() has switched branches, and egregore.json may differ
|
|
149
|
+
# between the branch the session opened on and the configured base. Reading
|
|
150
|
+
# late means the config that is actually checked out is the config that
|
|
151
|
+
# decides.
|
|
152
|
+
local _update_branch
|
|
153
|
+
_update_branch=$(git branch --show-current 2>/dev/null) || return 1
|
|
154
|
+
if [ "$_update_branch" != "$BASE_BRANCH" ]; then
|
|
155
|
+
return 1
|
|
156
|
+
fi
|
|
157
|
+
_AUTO_UPDATE=$(_read_auto_update)
|
|
158
|
+
if [ "$_UPSTREAM_URL" = "none" ] || [ "$_AUTO_UPDATE" != "true" ]; then
|
|
159
|
+
return 0
|
|
160
|
+
fi
|
|
161
|
+
if ! git show-ref --verify --quiet refs/remotes/upstream/main 2>/dev/null; then
|
|
162
|
+
return 0
|
|
163
|
+
fi
|
|
164
|
+
# Re-sync the base branch right before committing onto it: the warm-marker
|
|
165
|
+
# fast path can leave origin/$BASE_BRANCH up to ~10min stale, and an update
|
|
166
|
+
# committed onto a stale base creates divergence that later ff-only syncs
|
|
167
|
+
# cannot resolve. Only this rare path (upstream set + auto_update on) pays
|
|
168
|
+
# the fetch. FAIL CLOSED: if the fetch or fast-forward doesn't succeed
|
|
169
|
+
# (offline, or the base already diverged), skip the update entirely rather
|
|
170
|
+
# than commit upstream files onto a stale base — the next healthy boot
|
|
171
|
+
# applies it.
|
|
172
|
+
git fetch origin "$BASE_BRANCH" --quiet 2>/dev/null || return 0
|
|
173
|
+
git merge --ff-only "origin/$BASE_BRANCH" --quiet 2>/dev/null || return 0
|
|
174
|
+
# Apply upstream changes — checkout is idempotent, skip diff check
|
|
175
|
+
# (git diff with variable path lists breaks in zsh — no word-splitting)
|
|
176
|
+
for _p in bin/ .claude/commands/ .claude/skills/ .claude/hooks/ .claude/context/ .claude/agents/ loom/ CLAUDE.md skills/; do
|
|
177
|
+
git checkout upstream/main -- "$_p" 2>/dev/null || true
|
|
178
|
+
done
|
|
179
|
+
# Only commit if there are actual changes. Record WHAT changed before
|
|
180
|
+
# committing — an overwrite of local edits is the one outcome the user has
|
|
181
|
+
# to be able to see afterwards, and the commit is the only other record.
|
|
182
|
+
local _changed
|
|
183
|
+
_changed=$(git status --porcelain bin/ .claude/ loom/ CLAUDE.md skills/ 2>/dev/null)
|
|
184
|
+
if [ -n "$_changed" ]; then
|
|
185
|
+
FRAMEWORK_UPDATED_COUNT=$(printf '%s\n' "$_changed" | grep -c . || echo 0)
|
|
186
|
+
FRAMEWORK_UPDATED_FILES=$(printf '%s\n' "$_changed" | awk '{print $NF}' | head -3 | tr '\n' ' ')
|
|
187
|
+
git add bin/ .claude/ loom/ CLAUDE.md skills/ 2>/dev/null
|
|
188
|
+
EGREGORE_FRAMEWORK_UPDATE=1 git commit -m "Auto-update Egregore framework" --quiet 2>/dev/null || true
|
|
189
|
+
FRAMEWORK_UPDATED="true"
|
|
190
|
+
fi
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# --- Worktree prune (just clean git's internal list, don't delete anything) ---
|
|
194
|
+
git worktree prune 2>/dev/null || true
|
|
195
|
+
|
|
196
|
+
# --- Git health check ---
|
|
197
|
+
if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH" 2>/dev/null; then
|
|
198
|
+
HEALTH_GIT="ok"
|
|
199
|
+
else
|
|
200
|
+
HEALTH_GIT="fail"
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# --- Guarded staging -------------------------------------------------------
|
|
204
|
+
# git_add_guarded() lives in the shared lib so the /handoff auto-save uses the
|
|
205
|
+
# exact same logic. Fallback to plain `git add -A` if the lib can't be sourced,
|
|
206
|
+
# so an unattended auto-save never silently no-ops.
|
|
207
|
+
# shellcheck source=bin/lib/git-safe.sh
|
|
208
|
+
. "$SCRIPT_DIR/bin/lib/git-safe.sh" 2>/dev/null || true
|
|
209
|
+
if ! type git_add_guarded >/dev/null 2>&1; then
|
|
210
|
+
git_add_guarded() { git add -A 2>/dev/null || true; }
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# --- Setup base branch (wrapped — failures set HEALTH_GIT but don't crash) ---
|
|
214
|
+
# Named setup_develop for continuity; it operates on $BASE_BRANCH, which is
|
|
215
|
+
# "develop" by default and whatever egregore.json's base_branch says otherwise.
|
|
216
|
+
setup_develop() {
|
|
217
|
+
# Ensure the base branch exists locally
|
|
218
|
+
if ! git show-ref --verify --quiet "refs/heads/$BASE_BRANCH" 2>/dev/null; then
|
|
219
|
+
if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH" 2>/dev/null; then
|
|
220
|
+
git checkout -b "$BASE_BRANCH" "origin/$BASE_BRANCH" --quiet 2>/dev/null || return 1
|
|
221
|
+
else
|
|
222
|
+
# Not on the remote either — create it and publish it
|
|
223
|
+
git checkout -b "$BASE_BRANCH" --quiet 2>/dev/null || return 1
|
|
224
|
+
git push -u origin "$BASE_BRANCH" --quiet 2>/dev/null || return 1
|
|
225
|
+
fi
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# Sync the base branch (without checkout — safe for concurrent sessions)
|
|
229
|
+
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null) || return 1
|
|
230
|
+
|
|
231
|
+
# Update the local ref from remote without switching branches, using
|
|
232
|
+
# force-update to handle divergence (e.g., from auto-update commits).
|
|
233
|
+
# origin/$BASE_BRANCH is already current: either the parallel `git fetch
|
|
234
|
+
# origin` above ran this boot, or the attendant fetched within the freshness
|
|
235
|
+
# window. A second fetch here cost ~2s on every boot and never changed refs.
|
|
236
|
+
if [[ "$CURRENT_BRANCH" != "$BASE_BRANCH" ]]; then
|
|
237
|
+
# Safe to force-update when not checked out
|
|
238
|
+
git branch -f "$BASE_BRANCH" "origin/$BASE_BRANCH" 2>/dev/null || true
|
|
239
|
+
else
|
|
240
|
+
# On the base branch — try ff merge, fall back to reset only if no unpushed work
|
|
241
|
+
git merge --ff-only "origin/$BASE_BRANCH" --quiet 2>/dev/null || {
|
|
242
|
+
# Only reset if there are no unpushed commits and no dirty tracked work.
|
|
243
|
+
# A reset here runs before autosave and must never discard local changes.
|
|
244
|
+
LOCAL_AHEAD=$(git rev-list "origin/$BASE_BRANCH..$BASE_BRANCH" --count 2>/dev/null || echo "0")
|
|
245
|
+
if [ "$LOCAL_AHEAD" = "0" ] && [ -z "$(git status --porcelain 2>/dev/null)" ]; then
|
|
246
|
+
git reset --hard "origin/$BASE_BRANCH" --quiet 2>/dev/null || true
|
|
247
|
+
fi
|
|
248
|
+
}
|
|
249
|
+
fi
|
|
250
|
+
# Count commits on the base branch ahead of main. Meaningless in
|
|
251
|
+
# single-branch mode, where the base branch IS main.
|
|
252
|
+
COMMITS_AHEAD=0
|
|
253
|
+
if [ "$BASE_BRANCH" != "main" ] && git show-ref --verify --quiet refs/remotes/origin/main 2>/dev/null; then
|
|
254
|
+
COMMITS_AHEAD=$(git rev-list "origin/main..$BASE_BRANCH" --count 2>/dev/null || echo "0")
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
# Always start from the base branch
|
|
258
|
+
# Every session begins there. Claude creates a fresh topic branch
|
|
259
|
+
# (dev/{author}/{topic-slug}) when the user says what they're working on.
|
|
260
|
+
# If we're on a working branch with uncommitted work, save it first.
|
|
261
|
+
ACTION="ready"
|
|
262
|
+
SAVED_BRANCH=""
|
|
263
|
+
|
|
264
|
+
if [[ "$CURRENT_BRANCH" != "$BASE_BRANCH" ]]; then
|
|
265
|
+
# Check for uncommitted work (staged + unstaged + untracked in tracked dirs)
|
|
266
|
+
if [ -n "$(git status --porcelain 2>/dev/null | head -1)" ]; then
|
|
267
|
+
# Save uncommitted work so nothing is lost (guarded: never auto-commit
|
|
268
|
+
# stray submodule pointers from sibling repos in the checkout)
|
|
269
|
+
git_add_guarded
|
|
270
|
+
git commit -m "Auto-save: uncommitted work from $CURRENT_BRANCH" --quiet 2>/dev/null || true
|
|
271
|
+
SAVED_BRANCH="$CURRENT_BRANCH"
|
|
272
|
+
fi
|
|
273
|
+
|
|
274
|
+
# Push the branch if it has unpushed commits (so work is never only local)
|
|
275
|
+
if [[ "$CURRENT_BRANCH" == dev/* ]] || [[ "$CURRENT_BRANCH" == feature/* ]] || [[ "$CURRENT_BRANCH" == bugfix/* ]]; then
|
|
276
|
+
LOCAL_HEAD=$(git rev-parse HEAD 2>/dev/null || echo "")
|
|
277
|
+
REMOTE_HEAD=$(git rev-parse "origin/$CURRENT_BRANCH" 2>/dev/null || echo "none")
|
|
278
|
+
if [ "$LOCAL_HEAD" != "$REMOTE_HEAD" ]; then
|
|
279
|
+
git push origin "$CURRENT_BRANCH" --quiet 2>/dev/null || true
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# Switch to the base branch (already updated by the fetch above)
|
|
284
|
+
if ! git checkout "$BASE_BRANCH" --quiet 2>/dev/null; then
|
|
285
|
+
BRANCH=$(git branch --show-current 2>/dev/null || echo "?")
|
|
286
|
+
return 1
|
|
287
|
+
fi
|
|
288
|
+
else
|
|
289
|
+
# Already on it — fetch couldn't update a checked-out branch, so pull
|
|
290
|
+
git merge --ff-only "origin/$BASE_BRANCH" --quiet 2>/dev/null || true
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# Never report the intended branch as the actual branch. A checkout can fail
|
|
294
|
+
# when the base is held by another worktree or the index blocks the switch.
|
|
295
|
+
# setup_develop must fail in that case so callers cannot apply framework files
|
|
296
|
+
# to the user's working branch.
|
|
297
|
+
BRANCH=$(git branch --show-current 2>/dev/null || echo "?")
|
|
298
|
+
if [ "$BRANCH" != "$BASE_BRANCH" ]; then
|
|
299
|
+
return 1
|
|
300
|
+
fi
|
|
301
|
+
DEVELOP_SYNCED="true"
|
|
302
|
+
return 0
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Initialize defaults used by setup_develop
|
|
306
|
+
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
|
|
307
|
+
DEVELOP_SYNCED="false"
|
|
308
|
+
COMMITS_AHEAD=0
|
|
309
|
+
ACTION="ready"
|
|
310
|
+
SAVED_BRANCH=""
|
|
311
|
+
BRANCH="${CURRENT_BRANCH:-$BASE_BRANCH}"
|
|
312
|
+
BASE_BRANCH_READY="false"
|
|
313
|
+
|
|
314
|
+
if [ "$IS_WORKTREE" = "true" ]; then
|
|
315
|
+
# Inside a worktree — skip the base-branch checkout and framework update.
|
|
316
|
+
# Worktrees are isolated working copies; framework updates belong on the base.
|
|
317
|
+
BRANCH=$(git branch --show-current 2>/dev/null || echo "?")
|
|
318
|
+
DEVELOP_SYNCED="true"
|
|
319
|
+
|
|
320
|
+
# --- Worktree branch health check ---
|
|
321
|
+
# Detect if the branch was already merged into the base branch (e.g., PR
|
|
322
|
+
# merged but worktree not cleaned up). This prevents working on a stale
|
|
323
|
+
# branch whose commits already landed.
|
|
324
|
+
WORKTREE_STALE="false"
|
|
325
|
+
if [ "$BRANCH" != "?" ] && [ "$BRANCH" != "$BASE_BRANCH" ] && [ "$BRANCH" != "main" ]; then
|
|
326
|
+
# Check if remote branch still exists. When the attendant marker is fresh,
|
|
327
|
+
# local remote-tracking refs are authoritative (the attendant fetches with
|
|
328
|
+
# --prune every warm cycle) — answering locally saves a ~2s ls-remote
|
|
329
|
+
# round-trip on every worktree boot. Cold marker keeps the live query.
|
|
330
|
+
if [ "$_REFS_FRESH" = "true" ]; then
|
|
331
|
+
_BRANCH_ON_REMOTE() { git show-ref --verify --quiet "refs/remotes/origin/$BRANCH" 2>/dev/null; }
|
|
332
|
+
else
|
|
333
|
+
_BRANCH_ON_REMOTE() { git ls-remote --heads origin "$BRANCH" 2>/dev/null | grep -q "$BRANCH"; }
|
|
334
|
+
fi
|
|
335
|
+
if ! _BRANCH_ON_REMOTE; then
|
|
336
|
+
# Remote branch gone — check if it was merged into the base branch
|
|
337
|
+
if git branch -r --merged "origin/$BASE_BRANCH" 2>/dev/null | grep -q "origin/$BRANCH" 2>/dev/null || \
|
|
338
|
+
git merge-base --is-ancestor HEAD "origin/$BASE_BRANCH" 2>/dev/null; then
|
|
339
|
+
WORKTREE_STALE="merged"
|
|
340
|
+
else
|
|
341
|
+
WORKTREE_STALE="remote_deleted"
|
|
342
|
+
fi
|
|
343
|
+
fi
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
if [ "$WORKTREE_STALE" = "merged" ]; then
|
|
347
|
+
echo ""
|
|
348
|
+
echo "WARNING: Branch '$BRANCH' was already merged into $BASE_BRANCH."
|
|
349
|
+
echo "This worktree is stale — your work here is already in $BASE_BRANCH."
|
|
350
|
+
echo "Start a new session in the main project to get a fresh branch."
|
|
351
|
+
echo ""
|
|
352
|
+
HEALTH_GIT="fail"
|
|
353
|
+
elif [ "$WORKTREE_STALE" = "remote_deleted" ]; then
|
|
354
|
+
echo ""
|
|
355
|
+
echo "WARNING: Remote branch '$BRANCH' was deleted but NOT merged into $BASE_BRANCH."
|
|
356
|
+
echo "This worktree may contain unique local commits. Check before discarding:"
|
|
357
|
+
echo " git log origin/$BASE_BRANCH..HEAD --oneline"
|
|
358
|
+
echo ""
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# Use main project's .env and state if ours are missing
|
|
362
|
+
if [ ! -f "$SCRIPT_DIR/.env" ] && [ -f "$MAIN_PROJECT_DIR/.env" ]; then
|
|
363
|
+
export ENV_FILE="$MAIN_PROJECT_DIR/.env"
|
|
364
|
+
fi
|
|
365
|
+
elif setup_develop 2>/dev/null; then
|
|
366
|
+
BASE_BRANCH_READY="true"
|
|
367
|
+
else
|
|
368
|
+
HEALTH_GIT="fail"
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
# Apply a framework update only after setup verified the configured base branch.
|
|
372
|
+
if [ "$IS_WORKTREE" != "true" ] && [ "$BASE_BRANCH_READY" = "true" ]; then
|
|
373
|
+
_apply_framework_update 2>/dev/null || true
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
# --- Sync memory (symlink or direct directory — both valid) ---
|
|
377
|
+
if [ -d "$SCRIPT_DIR/memory/.git" ]; then
|
|
378
|
+
MEM_LOCAL=$(git -C "$SCRIPT_DIR/memory" rev-parse HEAD 2>/dev/null || echo "")
|
|
379
|
+
MEM_REMOTE=$(git -C "$SCRIPT_DIR/memory" rev-parse origin/main 2>/dev/null || echo "")
|
|
380
|
+
if [ -n "$MEM_LOCAL" ] && [ -n "$MEM_REMOTE" ] && [ "$MEM_LOCAL" != "$MEM_REMOTE" ]; then
|
|
381
|
+
git -C "$SCRIPT_DIR/memory" pull origin main --quiet 2>/dev/null || true
|
|
382
|
+
fi
|
|
383
|
+
MEMORY_SYNCED="true"
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
# --- Sync managed repos ---
|
|
387
|
+
# Managed repos sync silently — they are a CLI concern and never render in the
|
|
388
|
+
# greeting. REPOS_STATUS stays exported (empty) for consumers of this lib.
|
|
389
|
+
REPOS_STATUS=""
|
|
390
|
+
for REPO in $MANAGED_REPOS; do
|
|
391
|
+
REPO_DIR="$SCRIPT_DIR/../$REPO"
|
|
392
|
+
if [ -d "$REPO_DIR/.git" ]; then
|
|
393
|
+
# Resolve base branch for this repo (from egregore.json or auto-detect)
|
|
394
|
+
if ! REPO_BASE=$(_get_base_branch "$REPO"); then
|
|
395
|
+
HEALTH_GIT="fail"
|
|
396
|
+
continue
|
|
397
|
+
fi
|
|
398
|
+
# Sync base branch with remote (if not checked out)
|
|
399
|
+
R_BRANCH=$(git -C "$REPO_DIR" branch --show-current 2>/dev/null || echo "?")
|
|
400
|
+
if [ "$R_BRANCH" != "$REPO_BASE" ]; then
|
|
401
|
+
git -C "$REPO_DIR" branch -f "$REPO_BASE" "origin/$REPO_BASE" --quiet 2>/dev/null || true
|
|
402
|
+
else
|
|
403
|
+
git -C "$REPO_DIR" merge --ff-only "origin/$REPO_BASE" --quiet 2>/dev/null || true
|
|
404
|
+
fi
|
|
405
|
+
fi
|
|
406
|
+
done
|