create-egregore 0.17.4 → 0.18.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.
Files changed (106) hide show
  1. package/assets/egregore-launcher.js +1965 -0
  2. package/assets/egregore-launcher.sh +385 -0
  3. package/bin/cli.js +472 -81
  4. package/lib/api.js +2 -2
  5. package/lib/auth.js +255 -20
  6. package/lib/codex-runtime.js +268 -0
  7. package/lib/commands.js +31 -0
  8. package/lib/context.js +1 -1
  9. package/lib/local.js +616 -189
  10. package/lib/setup.js +822 -84
  11. package/lib/ui.js +780 -84
  12. package/package.json +12 -3
  13. package/runtime/codex/.codex/config.toml +15 -0
  14. package/runtime/codex/.codex/hooks/branch-guard.js +234 -0
  15. package/runtime/codex/.codex/hooks.json +17 -0
  16. package/runtime/codex/.codex/skills/activity/SKILL.md +70 -0
  17. package/runtime/codex/.codex/skills/add/SKILL.md +25 -0
  18. package/runtime/codex/.codex/skills/announce/SKILL.md +54 -0
  19. package/runtime/codex/.codex/skills/answer/SKILL.md +25 -0
  20. package/runtime/codex/.codex/skills/archive/SKILL.md +41 -0
  21. package/runtime/codex/.codex/skills/ask/SKILL.md +59 -0
  22. package/runtime/codex/.codex/skills/branch/SKILL.md +25 -0
  23. package/runtime/codex/.codex/skills/checkup/SKILL.md +41 -0
  24. package/runtime/codex/.codex/skills/commit/SKILL.md +25 -0
  25. package/runtime/codex/.codex/skills/contribute/SKILL.md +25 -0
  26. package/runtime/codex/.codex/skills/dark-mode/SKILL.md +25 -0
  27. package/runtime/codex/.codex/skills/dashboard/SKILL.md +59 -0
  28. package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +70 -0
  29. package/runtime/codex/.codex/skills/delete-user/SKILL.md +25 -0
  30. package/runtime/codex/.codex/skills/egregore-voice/SKILL.md +25 -0
  31. package/runtime/codex/.codex/skills/emissary/SKILL.md +41 -0
  32. package/runtime/codex/.codex/skills/env/SKILL.md +25 -0
  33. package/runtime/codex/.codex/skills/handoff/SKILL.md +67 -0
  34. package/runtime/codex/.codex/skills/harvest/SKILL.md +107 -0
  35. package/runtime/codex/.codex/skills/infra/SKILL.md +41 -0
  36. package/runtime/codex/.codex/skills/ingest/SKILL.md +25 -0
  37. package/runtime/codex/.codex/skills/ingest-google/SKILL.md +25 -0
  38. package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +41 -0
  39. package/runtime/codex/.codex/skills/invite/SKILL.md +40 -0
  40. package/runtime/codex/.codex/skills/issue/SKILL.md +41 -0
  41. package/runtime/codex/.codex/skills/me/SKILL.md +25 -0
  42. package/runtime/codex/.codex/skills/meeting/SKILL.md +41 -0
  43. package/runtime/codex/.codex/skills/note/SKILL.md +25 -0
  44. package/runtime/codex/.codex/skills/onboarding/SKILL.md +41 -0
  45. package/runtime/codex/.codex/skills/pr/SKILL.md +25 -0
  46. package/runtime/codex/.codex/skills/project/SKILL.md +41 -0
  47. package/runtime/codex/.codex/skills/pull/SKILL.md +25 -0
  48. package/runtime/codex/.codex/skills/push/SKILL.md +25 -0
  49. package/runtime/codex/.codex/skills/quest/SKILL.md +77 -0
  50. package/runtime/codex/.codex/skills/quest-suggest/SKILL.md +25 -0
  51. package/runtime/codex/.codex/skills/reflect/SKILL.md +41 -0
  52. package/runtime/codex/.codex/skills/review-pr/SKILL.md +41 -0
  53. package/runtime/codex/.codex/skills/save/SKILL.md +62 -0
  54. package/runtime/codex/.codex/skills/setup/SKILL.md +25 -0
  55. package/runtime/codex/.codex/skills/summon/SKILL.md +41 -0
  56. package/runtime/codex/.codex/skills/sync-repos/SKILL.md +25 -0
  57. package/runtime/codex/.codex/skills/telegram-connect/SKILL.md +25 -0
  58. package/runtime/codex/.codex/skills/telemetry/SKILL.md +25 -0
  59. package/runtime/codex/.codex/skills/test/SKILL.md +41 -0
  60. package/runtime/codex/.codex/skills/the-spiral/SKILL.md +84 -0
  61. package/runtime/codex/.codex/skills/todo/SKILL.md +41 -0
  62. package/runtime/codex/.codex/skills/tui-design/SKILL.md +41 -0
  63. package/runtime/codex/.codex/skills/tutorial/SKILL.md +41 -0
  64. package/runtime/codex/.codex/skills/update/SKILL.md +25 -0
  65. package/runtime/codex/.codex/skills/view/SKILL.md +41 -0
  66. package/runtime/codex/.codex/skills/visual-explain/SKILL.md +41 -0
  67. package/runtime/codex/.codex/skills/wrap/SKILL.md +55 -0
  68. package/runtime/codex/.codex/spec-manifest.json +108 -0
  69. package/runtime/codex/AGENTS.md +40 -0
  70. package/runtime/codex/bin/activity-data.sh +177 -0
  71. package/runtime/codex/bin/agent.sh +669 -0
  72. package/runtime/codex/bin/codex-install-skills.sh +78 -0
  73. package/runtime/codex/bin/codex-render-spec.mjs +308 -0
  74. package/runtime/codex/bin/codex-session-start.sh +238 -0
  75. package/runtime/codex/bin/codex-skill-render.mjs +315 -0
  76. package/runtime/codex/bin/codex-sync-skills.sh +223 -0
  77. package/runtime/codex/bin/dashboard-data.sh +174 -0
  78. package/runtime/codex/bin/graph-batch.sh +60 -0
  79. package/runtime/codex/bin/graph-op.sh +380 -0
  80. package/runtime/codex/bin/graph-wal.sh +228 -0
  81. package/runtime/codex/bin/graph.sh +141 -0
  82. package/runtime/codex/bin/handoff-pr-backfill.sh +86 -0
  83. package/runtime/codex/bin/handoff-run.sh +431 -0
  84. package/runtime/codex/bin/handoff-save-egregore.sh +131 -0
  85. package/runtime/codex/bin/index-handoff.sh +306 -0
  86. package/runtime/codex/bin/lib/artifact-id.sh +46 -0
  87. package/runtime/codex/bin/lib/config.sh +71 -0
  88. package/runtime/codex/bin/lib/context.sh +463 -0
  89. package/runtime/codex/bin/lib/dashboard-artifact.sh +142 -0
  90. package/runtime/codex/bin/lib/ensure-develop.sh +183 -0
  91. package/runtime/codex/bin/lib/git-sync.sh +262 -0
  92. package/runtime/codex/bin/lib/greeting.sh +414 -0
  93. package/runtime/codex/bin/lib/hash.sh +13 -0
  94. package/runtime/codex/bin/lib/identity.sh +164 -0
  95. package/runtime/codex/bin/lib/permissions.sh +106 -0
  96. package/runtime/codex/bin/lib/time.sh +56 -0
  97. package/runtime/codex/bin/lib/worktree-links.sh +54 -0
  98. package/runtime/codex/bin/notify.sh +207 -0
  99. package/runtime/codex/bin/publish-artifact.sh +173 -0
  100. package/runtime/codex/bin/publish-references.sh +144 -0
  101. package/runtime/codex/bin/repo-state.sh +99 -0
  102. package/runtime/codex/bin/telemetry.sh +350 -0
  103. package/runtime/codex/bin/worktree-create.sh +118 -0
  104. package/runtime/codex/bin/worktree-remove.sh +50 -0
  105. package/runtime/codex/bin/worktree.sh +198 -0
  106. package/runtime/codex/manifest.json +155 -0
@@ -0,0 +1,183 @@
1
+ #!/bin/bash
2
+ # ensure-develop.sh — Ensure a repository has a develop branch.
3
+ #
4
+ # Usage:
5
+ # bash bin/lib/ensure-develop.sh <repo-path>
6
+ # bash bin/lib/ensure-develop.sh <repo-path> --report
7
+ #
8
+ # Behavior:
9
+ # 1. Detects the repo's default branch (main, master, or HEAD)
10
+ # 2. Checks if develop exists locally and/or on origin
11
+ # 3. If missing, creates develop from the default branch and pushes it
12
+ #
13
+ # Flags:
14
+ # --report Print a JSON report of the repo's branching model instead of
15
+ # creating develop. Used by create-egregore to analyze existing repos.
16
+ #
17
+ # Exit codes:
18
+ # 0 — develop exists (already existed or was just created)
19
+ # 1 — could not create develop (no default branch, not a git repo, push failed)
20
+ #
21
+ # Output (on success, without --report):
22
+ # created:<default_branch> — develop was created from <default_branch>
23
+ # exists — develop already existed
24
+ #
25
+ # Output (with --report):
26
+ # JSON object with branching analysis
27
+
28
+ set -o pipefail
29
+
30
+ REPO_PATH="${1:-.}"
31
+ FLAG="${2:-}"
32
+
33
+ if [ ! -d "$REPO_PATH/.git" ] && [ ! -f "$REPO_PATH/.git" ]; then
34
+ echo "error:not_a_git_repo" >&2
35
+ exit 1
36
+ fi
37
+
38
+ # ── Detect default branch ──────────────────────────────────────────
39
+ # Priority: what origin/HEAD points to > main > master > first branch found
40
+ detect_default_branch() {
41
+ local repo="$1"
42
+
43
+ # 1. Check origin/HEAD (set by GitHub on clone)
44
+ local origin_head
45
+ origin_head=$(git -C "$repo" symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
46
+ if [ -n "$origin_head" ] && git -C "$repo" show-ref --verify --quiet "refs/remotes/origin/$origin_head" 2>/dev/null; then
47
+ echo "$origin_head"
48
+ return 0
49
+ fi
50
+
51
+ # 2. Check common names on remote
52
+ for branch in main master; do
53
+ if git -C "$repo" show-ref --verify --quiet "refs/remotes/origin/$branch" 2>/dev/null; then
54
+ echo "$branch"
55
+ return 0
56
+ fi
57
+ done
58
+
59
+ # 3. Check local branches (repo might not have a remote yet)
60
+ for branch in main master; do
61
+ if git -C "$repo" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
62
+ echo "$branch"
63
+ return 0
64
+ fi
65
+ done
66
+
67
+ # 4. Fall back to whatever HEAD points to
68
+ local head_branch
69
+ head_branch=$(git -C "$repo" branch --show-current 2>/dev/null)
70
+ if [ -n "$head_branch" ] && [ "$head_branch" != "develop" ]; then
71
+ echo "$head_branch"
72
+ return 0
73
+ fi
74
+
75
+ return 1
76
+ }
77
+
78
+ # ── Report mode ─────────────────────────────────────────────────────
79
+ if [ "$FLAG" = "--report" ]; then
80
+ default_branch=$(detect_default_branch "$REPO_PATH" 2>/dev/null || echo "")
81
+ has_develop_local="false"
82
+ has_develop_remote="false"
83
+ git -C "$REPO_PATH" show-ref --verify --quiet refs/heads/develop 2>/dev/null && has_develop_local="true"
84
+ git -C "$REPO_PATH" show-ref --verify --quiet refs/remotes/origin/develop 2>/dev/null && has_develop_remote="true"
85
+
86
+ # Count remote branches (excluding HEAD)
87
+ branch_count=$(git -C "$REPO_PATH" branch -r 2>/dev/null | grep -cv 'HEAD' 2>/dev/null || echo "0")
88
+ [ -z "$branch_count" ] && branch_count=0
89
+
90
+ # List remote branch names (excluding origin/HEAD, max 20)
91
+ _branch_list=$(git -C "$REPO_PATH" branch -r --format='%(refname:short)' 2>/dev/null \
92
+ | grep -v 'origin/HEAD' \
93
+ | sed 's|^origin/||' \
94
+ | head -20)
95
+ if [ -n "$_branch_list" ]; then
96
+ branches=$(echo "$_branch_list" | jq -R . | jq -s .)
97
+ else
98
+ branches="[]"
99
+ fi
100
+
101
+ # Detect active contributors from branch names (dev/author/... pattern)
102
+ _contrib_list=$(git -C "$REPO_PATH" branch -r --format='%(refname:short)' 2>/dev/null \
103
+ | grep -E '^origin/dev/' \
104
+ | sed 's|^origin/dev/||; s|/.*||' \
105
+ | sort -u)
106
+ if [ -n "$_contrib_list" ]; then
107
+ contributors=$(echo "$_contrib_list" | jq -R . | jq -s .)
108
+ else
109
+ contributors="[]"
110
+ fi
111
+
112
+ jq -n \
113
+ --arg default_branch "$default_branch" \
114
+ --argjson has_develop_local "$has_develop_local" \
115
+ --argjson has_develop_remote "$has_develop_remote" \
116
+ --argjson branch_count "$branch_count" \
117
+ --argjson branches "$branches" \
118
+ --argjson contributors "$contributors" \
119
+ '{
120
+ default_branch: $default_branch,
121
+ has_develop_local: $has_develop_local,
122
+ has_develop_remote: $has_develop_remote,
123
+ branch_count: $branch_count,
124
+ branches: $branches,
125
+ contributors: $contributors,
126
+ needs_develop: (($has_develop_remote | not) and ($has_develop_local | not))
127
+ }'
128
+ exit 0
129
+ fi
130
+
131
+ # ── Ensure develop exists ──────────────────────────────────────────
132
+
133
+ # Already exists on remote?
134
+ if git -C "$REPO_PATH" show-ref --verify --quiet refs/remotes/origin/develop 2>/dev/null; then
135
+ # Ensure local tracking branch exists too
136
+ if ! git -C "$REPO_PATH" show-ref --verify --quiet refs/heads/develop 2>/dev/null; then
137
+ git -C "$REPO_PATH" branch develop origin/develop --quiet 2>/dev/null || true
138
+ fi
139
+ echo "exists"
140
+ exit 0
141
+ fi
142
+
143
+ # Already exists locally but not on remote? Push it.
144
+ if git -C "$REPO_PATH" show-ref --verify --quiet refs/heads/develop 2>/dev/null; then
145
+ if git -C "$REPO_PATH" push -u origin develop --quiet 2>/dev/null; then
146
+ echo "exists"
147
+ exit 0
148
+ fi
149
+ # Push failed but local exists — still usable
150
+ echo "exists:local_only"
151
+ exit 0
152
+ fi
153
+
154
+ # Need to create develop from default branch
155
+ DEFAULT_BRANCH=$(detect_default_branch "$REPO_PATH")
156
+ if [ -z "$DEFAULT_BRANCH" ]; then
157
+ echo "error:no_default_branch" >&2
158
+ exit 1
159
+ fi
160
+
161
+ # Create develop from the default branch
162
+ # Prefer remote ref if available (more up-to-date after fetch)
163
+ if git -C "$REPO_PATH" show-ref --verify --quiet "refs/remotes/origin/$DEFAULT_BRANCH" 2>/dev/null; then
164
+ git -C "$REPO_PATH" branch develop "origin/$DEFAULT_BRANCH" --quiet 2>/dev/null
165
+ else
166
+ git -C "$REPO_PATH" branch develop "$DEFAULT_BRANCH" --quiet 2>/dev/null
167
+ fi
168
+
169
+ if [ $? -ne 0 ]; then
170
+ echo "error:branch_create_failed" >&2
171
+ exit 1
172
+ fi
173
+
174
+ # Push to remote
175
+ if git -C "$REPO_PATH" push -u origin develop --quiet 2>/dev/null; then
176
+ echo "created:$DEFAULT_BRANCH"
177
+ exit 0
178
+ else
179
+ # Push failed — develop exists locally but not on remote
180
+ # This is still usable; session-start.sh will retry the push
181
+ echo "created:$DEFAULT_BRANCH:local_only"
182
+ exit 0
183
+ fi
@@ -0,0 +1,262 @@
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, MANAGED_REPOS (not yet set — read from config here)
15
+ # Outputs: HEALTH_GIT, DEVELOP_SYNCED, COMMITS_AHEAD, ACTION, SAVED_BRANCH,
16
+ # BRANCH, MEMORY_SYNCED, REPOS_STATUS, MANAGED_REPOS, CURRENT_BRANCH,
17
+ # FRAMEWORK_UPDATED
18
+
19
+ FRAMEWORK_UPDATED="false"
20
+
21
+ # --- Ensure pull.rebase is set (prevents "divergent branches" errors) ---
22
+ git config pull.rebase true 2>/dev/null || true
23
+
24
+ # --- Fetch all remotes in parallel ---
25
+ # Set git transfer timeout so hangs don't block startup indefinitely.
26
+ export GIT_HTTP_LOW_SPEED_LIMIT=1000 # abort if <1KB/s
27
+ export GIT_HTTP_LOW_SPEED_TIME=10 # for 10 seconds
28
+
29
+ git fetch origin --quiet 2>/dev/null &
30
+
31
+ # Fetch upstream framework (for update check — non-blocking)
32
+ # Default: official egregore-core repo. Set upstream_url in egregore.json to override,
33
+ # or set it to "none" to disable (e.g., in the dev repo where this IS the source).
34
+ _UPSTREAM_URL=$(jq -r '.upstream_url // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
35
+ [ -z "$_UPSTREAM_URL" ] && _UPSTREAM_URL="https://github.com/egregore-labs/egregore.git"
36
+ if [ "$_UPSTREAM_URL" != "none" ]; then
37
+ git remote add upstream "$_UPSTREAM_URL" 2>/dev/null || true
38
+ git fetch upstream main --quiet 2>/dev/null &
39
+ fi
40
+
41
+ # Sync memory in parallel (symlink or direct directory — both valid)
42
+ MEMORY_SYNCED="false"
43
+ if [ -d "$SCRIPT_DIR/memory/.git" ]; then
44
+ git -C "$SCRIPT_DIR/memory" fetch origin --quiet 2>/dev/null &
45
+ fi
46
+
47
+ # Fetch managed repos in parallel
48
+ MANAGED_REPOS=$(jq -r '(.repos[]? // empty) | if type == "object" then .name else . end' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
49
+ for REPO in $MANAGED_REPOS; do
50
+ if [ -d "$SCRIPT_DIR/../$REPO/.git" ]; then
51
+ git -C "$SCRIPT_DIR/../$REPO" fetch origin --quiet 2>/dev/null &
52
+ fi
53
+ done
54
+
55
+ # Wait for all fetches
56
+ wait 2>/dev/null || true
57
+
58
+ # --- Auto-update framework from upstream (deferred) ---
59
+ # Moved AFTER setup_develop() so framework commits land on develop, not on
60
+ # working branches. See _apply_framework_update() below.
61
+ _AUTO_UPDATE=$(jq -r '.auto_update // true' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
62
+
63
+ _apply_framework_update() {
64
+ # Applies framework paths from upstream to the CURRENT branch (must be develop).
65
+ # Disable with "auto_update": false in egregore.json.
66
+ # Dev repos (upstream_url: "none") skip this entirely.
67
+ if [ "$_UPSTREAM_URL" = "none" ] || [ "$_AUTO_UPDATE" = "false" ]; then
68
+ return 0
69
+ fi
70
+ if ! git show-ref --verify --quiet refs/remotes/upstream/main 2>/dev/null; then
71
+ return 0
72
+ fi
73
+ # Apply upstream changes — checkout is idempotent, skip diff check
74
+ # (git diff with variable path lists breaks in zsh — no word-splitting)
75
+ for _p in bin/ .claude/commands/ .claude/skills/ .claude/hooks/ .claude/context/ CLAUDE.md skills/; do
76
+ git checkout upstream/main -- "$_p" 2>/dev/null || true
77
+ done
78
+ # Only commit if there are actual changes
79
+ if [ -n "$(git status --porcelain bin/ .claude/ CLAUDE.md skills/ 2>/dev/null | head -1)" ]; then
80
+ git add bin/ .claude/ CLAUDE.md skills/ 2>/dev/null
81
+ EGREGORE_FRAMEWORK_UPDATE=1 git commit -m "Auto-update Egregore framework" --quiet 2>/dev/null || true
82
+ FRAMEWORK_UPDATED="true"
83
+ fi
84
+ }
85
+
86
+ # --- Worktree prune (just clean git's internal list, don't delete anything) ---
87
+ git worktree prune 2>/dev/null || true
88
+
89
+ # --- Git health check ---
90
+ if git show-ref --verify --quiet refs/remotes/origin/develop 2>/dev/null; then
91
+ HEALTH_GIT="ok"
92
+ else
93
+ HEALTH_GIT="fail"
94
+ fi
95
+
96
+ # --- Setup develop (wrapped — failures set HEALTH_GIT but don't crash) ---
97
+ setup_develop() {
98
+ # Ensure develop branch exists locally
99
+ if ! git show-ref --verify --quiet refs/heads/develop 2>/dev/null; then
100
+ if git show-ref --verify --quiet refs/remotes/origin/develop 2>/dev/null; then
101
+ git checkout -b develop origin/develop --quiet 2>/dev/null
102
+ else
103
+ # No develop on remote either — create from main
104
+ git checkout -b develop --quiet 2>/dev/null
105
+ git push -u origin develop --quiet 2>/dev/null
106
+ fi
107
+ fi
108
+
109
+ # Sync develop (without checkout — safe for concurrent sessions)
110
+ CURRENT_BRANCH=$(git branch --show-current)
111
+
112
+ # Update local develop ref from remote without switching branches
113
+ # Use fetch + force-update to handle divergence (e.g., from auto-update commits)
114
+ git fetch origin develop --quiet 2>/dev/null || true
115
+ if [[ "$CURRENT_BRANCH" != "develop" ]]; then
116
+ # Safe to force-update when not checked out
117
+ git branch -f develop origin/develop 2>/dev/null || true
118
+ else
119
+ # On develop — try ff merge, fall back to reset only if no unpushed work
120
+ git merge --ff-only origin/develop --quiet 2>/dev/null || {
121
+ # Only reset if there are no unpushed commits on develop
122
+ LOCAL_AHEAD=$(git rev-list origin/develop..develop --count 2>/dev/null || echo "0")
123
+ if [ "$LOCAL_AHEAD" = "0" ]; then
124
+ git reset --hard origin/develop --quiet 2>/dev/null || true
125
+ fi
126
+ }
127
+ fi
128
+ DEVELOP_SYNCED="true"
129
+
130
+ # Count commits on develop ahead of main
131
+ COMMITS_AHEAD=0
132
+ if git show-ref --verify --quiet refs/remotes/origin/main 2>/dev/null; then
133
+ COMMITS_AHEAD=$(git rev-list origin/main..develop --count 2>/dev/null || echo "0")
134
+ fi
135
+
136
+ # Always start from develop
137
+ # Every session begins on develop. Claude creates a fresh topic branch
138
+ # (dev/{author}/{topic-slug}) when the user says what they're working on.
139
+ # If we're on a working branch with uncommitted work, save it first.
140
+ ACTION="ready"
141
+ SAVED_BRANCH=""
142
+
143
+ if [[ "$CURRENT_BRANCH" != "develop" ]]; then
144
+ # Check for uncommitted work (staged + unstaged + untracked in tracked dirs)
145
+ if [ -n "$(git status --porcelain 2>/dev/null | head -1)" ]; then
146
+ # Save uncommitted work so nothing is lost
147
+ git add -A 2>/dev/null
148
+ git commit -m "Auto-save: uncommitted work from $CURRENT_BRANCH" --quiet 2>/dev/null || true
149
+ SAVED_BRANCH="$CURRENT_BRANCH"
150
+ fi
151
+
152
+ # Push the branch if it has unpushed commits (so work is never only local)
153
+ if [[ "$CURRENT_BRANCH" == dev/* ]] || [[ "$CURRENT_BRANCH" == feature/* ]] || [[ "$CURRENT_BRANCH" == bugfix/* ]]; then
154
+ LOCAL_HEAD=$(git rev-parse HEAD 2>/dev/null || echo "")
155
+ REMOTE_HEAD=$(git rev-parse "origin/$CURRENT_BRANCH" 2>/dev/null || echo "none")
156
+ if [ "$LOCAL_HEAD" != "$REMOTE_HEAD" ]; then
157
+ git push origin "$CURRENT_BRANCH" --quiet 2>/dev/null || true
158
+ fi
159
+ fi
160
+
161
+ # Switch to develop (already updated by fetch origin develop:develop above)
162
+ git checkout develop --quiet 2>/dev/null || true
163
+ else
164
+ # Already on develop — fetch couldn't update it (checked-out branch), so pull
165
+ git merge --ff-only origin/develop --quiet 2>/dev/null || true
166
+ fi
167
+
168
+ BRANCH="develop"
169
+ }
170
+
171
+ # Initialize defaults used by setup_develop
172
+ CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
173
+ DEVELOP_SYNCED="false"
174
+ COMMITS_AHEAD=0
175
+ ACTION="ready"
176
+ SAVED_BRANCH=""
177
+ BRANCH="${CURRENT_BRANCH:-develop}"
178
+
179
+ if [ "$IS_WORKTREE" = "true" ]; then
180
+ # Inside a worktree — skip develop checkout and framework update.
181
+ # Worktrees are isolated working copies; framework updates belong on develop.
182
+ BRANCH=$(git branch --show-current 2>/dev/null || echo "?")
183
+ DEVELOP_SYNCED="true"
184
+
185
+ # --- Worktree branch health check ---
186
+ # Detect if the branch was already merged into develop (e.g., PR merged
187
+ # but worktree not cleaned up). This prevents working on a stale branch
188
+ # whose commits are already in develop.
189
+ WORKTREE_STALE="false"
190
+ if [ "$BRANCH" != "?" ] && [ "$BRANCH" != "develop" ] && [ "$BRANCH" != "main" ]; then
191
+ # Check if remote branch still exists
192
+ if ! git ls-remote --heads origin "$BRANCH" 2>/dev/null | grep -q "$BRANCH"; then
193
+ # Remote branch gone — check if it was merged into develop
194
+ if git branch -r --merged origin/develop 2>/dev/null | grep -q "origin/$BRANCH" 2>/dev/null || \
195
+ git merge-base --is-ancestor HEAD origin/develop 2>/dev/null; then
196
+ WORKTREE_STALE="merged"
197
+ else
198
+ WORKTREE_STALE="remote_deleted"
199
+ fi
200
+ fi
201
+ fi
202
+
203
+ if [ "$WORKTREE_STALE" = "merged" ]; then
204
+ echo ""
205
+ echo "WARNING: Branch '$BRANCH' was already merged into develop."
206
+ echo "This worktree is stale — your work here is already in develop."
207
+ echo "Start a new session in the main project to get a fresh branch."
208
+ echo ""
209
+ HEALTH_GIT="fail"
210
+ elif [ "$WORKTREE_STALE" = "remote_deleted" ]; then
211
+ echo ""
212
+ echo "WARNING: Remote branch '$BRANCH' was deleted but NOT merged into develop."
213
+ echo "This worktree may contain unique local commits. Check before discarding:"
214
+ echo " git log origin/develop..HEAD --oneline"
215
+ echo ""
216
+ fi
217
+
218
+ # Use main project's .env and state if ours are missing
219
+ if [ ! -f "$SCRIPT_DIR/.env" ] && [ -f "$MAIN_PROJECT_DIR/.env" ]; then
220
+ export ENV_FILE="$MAIN_PROJECT_DIR/.env"
221
+ fi
222
+ elif ! setup_develop 2>/dev/null; then
223
+ HEALTH_GIT="fail"
224
+ fi
225
+
226
+ # Apply framework update now — we're on develop (or worktree skipped above)
227
+ if [ "$IS_WORKTREE" != "true" ]; then
228
+ _apply_framework_update 2>/dev/null || true
229
+ fi
230
+
231
+ # --- Sync memory (symlink or direct directory — both valid) ---
232
+ if [ -d "$SCRIPT_DIR/memory/.git" ]; then
233
+ MEM_LOCAL=$(git -C "$SCRIPT_DIR/memory" rev-parse HEAD 2>/dev/null || echo "")
234
+ MEM_REMOTE=$(git -C "$SCRIPT_DIR/memory" rev-parse origin/main 2>/dev/null || echo "")
235
+ if [ -n "$MEM_LOCAL" ] && [ -n "$MEM_REMOTE" ] && [ "$MEM_LOCAL" != "$MEM_REMOTE" ]; then
236
+ git -C "$SCRIPT_DIR/memory" pull origin main --quiet 2>/dev/null || true
237
+ fi
238
+ MEMORY_SYNCED="true"
239
+ fi
240
+
241
+ # --- Sync managed repos ---
242
+ REPOS_STATUS=""
243
+ for REPO in $MANAGED_REPOS; do
244
+ REPO_DIR="$SCRIPT_DIR/../$REPO"
245
+ if [ -d "$REPO_DIR/.git" ]; then
246
+ # Resolve base branch for this repo (from egregore.json or auto-detect)
247
+ REPO_BASE=$(_get_base_branch "$REPO")
248
+ # Sync base branch with remote (if not checked out)
249
+ R_BRANCH=$(git -C "$REPO_DIR" branch --show-current 2>/dev/null || echo "?")
250
+ if [ "$R_BRANCH" != "$REPO_BASE" ]; then
251
+ git -C "$REPO_DIR" branch -f "$REPO_BASE" "origin/$REPO_BASE" --quiet 2>/dev/null || true
252
+ else
253
+ git -C "$REPO_DIR" merge --ff-only "origin/$REPO_BASE" --quiet 2>/dev/null || true
254
+ fi
255
+ # Collect status
256
+ R_DIRTY=""
257
+ if [ -n "$(git -C "$REPO_DIR" status --porcelain 2>/dev/null | head -1)" ]; then
258
+ R_DIRTY=" *"
259
+ fi
260
+ REPOS_STATUS="${REPOS_STATUS} ◇ ${REPO}: ${R_BRANCH}${R_DIRTY}\n"
261
+ fi
262
+ done