create-egregore 0.19.32 → 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 +48 -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 +5 -4
- 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 +8 -1
- package/runtime/codex/bin/connect-refresh.sh +33 -0
- 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 +8 -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 +8 -1
- package/runtime/pi/bin/connect-refresh.sh +33 -0
- 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 +8 -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,242 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# dashboard-artifact.sh — Generate a session dashboard artifact with a shareable URL
|
|
3
|
+
#
|
|
4
|
+
# Runs after context.sh (all $CTX_DIR/* files populated), before greeting.sh.
|
|
5
|
+
# Compiles gathered context into a markdown document, generates HTML via
|
|
6
|
+
# egregore-artifacts, publishes it, and exports DASHBOARD_URL for greeting.sh.
|
|
7
|
+
#
|
|
8
|
+
# Inputs: SCRIPT_DIR, CTX_DIR, AUTHOR, GREETING_NAME, LOCAL_MODE,
|
|
9
|
+
# EGREGORE_SESSION_ID, FIRST_SESSION
|
|
10
|
+
# Outputs: DASHBOARD_URL (exported for greeting.sh)
|
|
11
|
+
|
|
12
|
+
DASHBOARD_URL=""
|
|
13
|
+
|
|
14
|
+
# Skip conditions: first session, onboarding incomplete, no session ID
|
|
15
|
+
if [ "${FIRST_SESSION:-false}" = "true" ]; then
|
|
16
|
+
return 0 2>/dev/null || exit 0
|
|
17
|
+
fi
|
|
18
|
+
if [ -z "${EGREGORE_SESSION_ID:-}" ]; then
|
|
19
|
+
return 0 2>/dev/null || exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# --- Read gathered context ---
|
|
23
|
+
_DB_ADDRESSED=$(cat "$CTX_DIR/addressed_rich" 2>/dev/null || echo "[]")
|
|
24
|
+
_DB_ADDR_COUNT=$(echo "$_DB_ADDRESSED" | jq 'length' 2>/dev/null || echo "0")
|
|
25
|
+
_DB_QUESTS=$(cat "$CTX_DIR/quests" 2>/dev/null || echo "[]")
|
|
26
|
+
_DB_QUEST_COUNT=$(echo "$_DB_QUESTS" | jq 'length' 2>/dev/null || echo "0")
|
|
27
|
+
_DB_TEAM=$(cat "$CTX_DIR/team" 2>/dev/null || echo "[]")
|
|
28
|
+
_DB_TEAM_COUNT=$(echo "$_DB_TEAM" | jq 'length' 2>/dev/null || echo "0")
|
|
29
|
+
_DB_LIFECYCLE=$(cat "$CTX_DIR/lifecycle" 2>/dev/null || echo '{}')
|
|
30
|
+
_DB_MERGED_COUNT=$(echo "$_DB_LIFECYCLE" | jq '.merged_prs.values // [] | length' 2>/dev/null || echo "0")
|
|
31
|
+
_DB_IMPL_COUNT=$(echo "$_DB_LIFECYCLE" | jq '.implemented_handoffs.values // [] | length' 2>/dev/null || echo "0")
|
|
32
|
+
_DB_PULSE=$(cat "$CTX_DIR/pulse_brief" 2>/dev/null || echo '{}')
|
|
33
|
+
_DB_PULSE_BRIEF=$(echo "$_DB_PULSE" | jq -r '.brief // empty' 2>/dev/null || true)
|
|
34
|
+
|
|
35
|
+
# Skip if all context is empty — nothing worth showing
|
|
36
|
+
_DB_HAS_CONTENT="false"
|
|
37
|
+
if [ "$_DB_ADDR_COUNT" -gt 0 ] 2>/dev/null; then _DB_HAS_CONTENT="true"; fi
|
|
38
|
+
if [ "$_DB_QUEST_COUNT" -gt 0 ] 2>/dev/null; then _DB_HAS_CONTENT="true"; fi
|
|
39
|
+
if [ "$_DB_TEAM_COUNT" -gt 0 ] 2>/dev/null; then _DB_HAS_CONTENT="true"; fi
|
|
40
|
+
if [ "$_DB_MERGED_COUNT" -gt 0 ] 2>/dev/null; then _DB_HAS_CONTENT="true"; fi
|
|
41
|
+
if [ "$_DB_IMPL_COUNT" -gt 0 ] 2>/dev/null; then _DB_HAS_CONTENT="true"; fi
|
|
42
|
+
|
|
43
|
+
if [ "$_DB_HAS_CONTENT" = "false" ]; then
|
|
44
|
+
return 0 2>/dev/null || exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# --- Compile markdown ---
|
|
48
|
+
_DB_DATE=$(date +%Y-%m-%d)
|
|
49
|
+
_DB_ORG=$(jq -r '.org_name // "Egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "Egregore")
|
|
50
|
+
_DB_MD="/tmp/egregore-dashboard-${EGREGORE_SESSION_ID}.md"
|
|
51
|
+
mkdir -p /tmp
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
printf '# Session Dashboard — %s\n\n' "$_DB_ORG"
|
|
55
|
+
|
|
56
|
+
# --- Pulse Brief (first — sets the tone) ---
|
|
57
|
+
if [ -n "$_DB_PULSE_BRIEF" ]; then
|
|
58
|
+
printf '## Pulse\n\n'
|
|
59
|
+
printf '✦ %s\n\n' "$_DB_PULSE_BRIEF"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# --- Handoffs & Asks (dense format matching terminal TUI) ---
|
|
63
|
+
if [ "$_DB_ADDR_COUNT" -gt 0 ] 2>/dev/null; then
|
|
64
|
+
printf '## Handoffs & Asks\n\n'
|
|
65
|
+
_DB_NOW_SEC=$(date +%s)
|
|
66
|
+
echo "$_DB_ADDRESSED" | jq -r '.[] | "\(.author // "unknown")\t\(.topic // "Untitled")\t\(.date // "--")"' 2>/dev/null | while IFS=$'\t' read -r _HF_AUTHOR _HF_TOPIC _HF_DATE; do
|
|
67
|
+
[ -z "$_HF_AUTHOR" ] && continue
|
|
68
|
+
# Compute relative time
|
|
69
|
+
_HF_DATE_ONLY="${_HF_DATE%%T*}"
|
|
70
|
+
_HF_EPOCH=$(date -j -f "%Y-%m-%d" "$_HF_DATE_ONLY" +%s 2>/dev/null || \
|
|
71
|
+
date -d "$_HF_DATE_ONLY" +%s 2>/dev/null || echo "0")
|
|
72
|
+
_HF_DAYS=$(( (_DB_NOW_SEC - _HF_EPOCH) / 86400 ))
|
|
73
|
+
if [ "$_HF_DAYS" -le 0 ] 2>/dev/null; then _HF_AGO="today"
|
|
74
|
+
elif [ "$_HF_DAYS" -eq 1 ] 2>/dev/null; then _HF_AGO="yesterday"
|
|
75
|
+
else _HF_AGO="${_HF_DAYS}d ago"
|
|
76
|
+
fi
|
|
77
|
+
_HF_NAME_LC=$(printf '%s' "$_HF_AUTHOR" | awk '{print tolower($1)}')
|
|
78
|
+
printf '● %s → you: %s (%s)\n\n' "$_HF_NAME_LC" "$_HF_TOPIC" "$_HF_AGO"
|
|
79
|
+
done
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# --- Team Activity (right after handoffs, recent only) ---
|
|
83
|
+
if [ "$_DB_TEAM_COUNT" -gt 0 ] 2>/dev/null; then
|
|
84
|
+
_DB_NOW=$(date +%s)
|
|
85
|
+
_DB_RECENCY=$((7 * 86400))
|
|
86
|
+
_DB_TEAM_FILTERED=$(echo "$_DB_TEAM" | jq --argjson now "$_DB_NOW" --argjson window "$_DB_RECENCY" \
|
|
87
|
+
'[.[] | select(.last_seen_sort > 0 and ($now - .last_seen_sort) < $window)]' 2>/dev/null || echo "[]")
|
|
88
|
+
_DB_TEAM_FCOUNT=$(echo "$_DB_TEAM_FILTERED" | jq 'length' 2>/dev/null || echo "0")
|
|
89
|
+
if [ "$_DB_TEAM_FCOUNT" -gt 0 ] 2>/dev/null; then
|
|
90
|
+
printf '## Team Activity\n\n'
|
|
91
|
+
printf '| Name | Last Seen | Working On |\n'
|
|
92
|
+
printf '|------|-----------|------------|\n'
|
|
93
|
+
echo "$_DB_TEAM_FILTERED" | jq -r '.[] | ((.working_on // "")) as $w | (.branches // []) as $b | "| \(.name) | \(.last_seen) | \(if $w != "" then $w else ($b | join(", ")) end) |"' 2>/dev/null || true
|
|
94
|
+
printf '\n'
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# --- What Changed ---
|
|
99
|
+
if [ "$_DB_MERGED_COUNT" -gt 0 ] 2>/dev/null || [ "$_DB_IMPL_COUNT" -gt 0 ] 2>/dev/null; then
|
|
100
|
+
printf '## What Changed\n\n'
|
|
101
|
+
if [ "$_DB_MERGED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
102
|
+
echo "$_DB_LIFECYCLE" | jq -r '.merged_prs.values[]? | "- ✓ PR #\(.[0]) \(.[2] // .[1] // "")"' 2>/dev/null || true
|
|
103
|
+
fi
|
|
104
|
+
if [ "$_DB_IMPL_COUNT" -gt 0 ] 2>/dev/null; then
|
|
105
|
+
echo "$_DB_LIFECYCLE" | jq -r '.implemented_handoffs.values[]? | "- ✓ \(.[1] // "someone") worked on: \(.[0] // "handoff")"' 2>/dev/null || true
|
|
106
|
+
fi
|
|
107
|
+
printf '\n'
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# --- Active Quests (bottom — reference, exclude meta entries) ---
|
|
111
|
+
if [ "$_DB_QUEST_COUNT" -gt 0 ] 2>/dev/null; then
|
|
112
|
+
_DB_QUESTS_FILTERED=$(echo "$_DB_QUESTS" | jq '[.[] | select(. != "_template" and . != "index")][:10]' 2>/dev/null || echo "[]")
|
|
113
|
+
_DB_QF_COUNT=$(echo "$_DB_QUESTS_FILTERED" | jq 'length' 2>/dev/null || echo "0")
|
|
114
|
+
if [ "$_DB_QF_COUNT" -gt 0 ] 2>/dev/null; then
|
|
115
|
+
printf '## Active Quests\n\n'
|
|
116
|
+
echo "$_DB_QUESTS_FILTERED" | jq -r '.[] | "- \(.)"' 2>/dev/null || true
|
|
117
|
+
printf '\n'
|
|
118
|
+
fi
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
} > "$_DB_MD" 2>/dev/null
|
|
122
|
+
|
|
123
|
+
# --- Publish markdown → HTML → hosted URL ---
|
|
124
|
+
# publish-artifact.sh handles HTML generation internally (npx egregore-artifacts)
|
|
125
|
+
# then uploads. Don't pre-generate HTML — that causes double-wrapping.
|
|
126
|
+
# https:// URLs are universally cmd+clickable across all terminal emulators.
|
|
127
|
+
#
|
|
128
|
+
# Connected mode publishes to a STABLE per-user artifact id and runs the
|
|
129
|
+
# render+upload detached: the URL is known up front, so the greeting prints it
|
|
130
|
+
# without paying the ~2s render/upload on the boot path. Content lands moments
|
|
131
|
+
# later; until then (and through the ~5min edge cache) the URL serves the
|
|
132
|
+
# previous session's dashboard, which is an acceptable trade for a greeting
|
|
133
|
+
# link. This also stops every boot from minting a new artifact URL.
|
|
134
|
+
#
|
|
135
|
+
# The id is RANDOM, generated once and persisted in the user's state file —
|
|
136
|
+
# never derived from the username. Dashboard reads are public and unauth'd,
|
|
137
|
+
# so a predictable id (org slug + github handle) would make every teammate's
|
|
138
|
+
# operational dashboard enumerable; and a name-derived id without an org
|
|
139
|
+
# component collides across orgs for multi-org users (artifact ids upsert
|
|
140
|
+
# globally). Random-per-instance gives unguessable AND collision-free.
|
|
141
|
+
_DB_SLUG=$(jq -r '.slug // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
142
|
+
_DB_STATE="${STATE_FILE:-$SCRIPT_DIR/.egregore-state.json}"
|
|
143
|
+
_DB_ID=$(jq -r '.dashboard_artifact_id // empty' "$_DB_STATE" 2>/dev/null)
|
|
144
|
+
if [ -z "$_DB_ID" ] && [ -f "$_DB_STATE" ]; then
|
|
145
|
+
# First-id creation is SERIALIZED (mkdir is the portable atomic primitive):
|
|
146
|
+
# without a lock, two first boots can each persist-then-adopt different ids
|
|
147
|
+
# and both publish, stranding an orphan stable artifact. The winner creates
|
|
148
|
+
# exactly one id; the loser re-reads and either adopts it or (readback still
|
|
149
|
+
# empty) falls through to the legacy synchronous publish for this boot.
|
|
150
|
+
# A crashed creator's stale lock breaks after 5 minutes.
|
|
151
|
+
_DB_LOCK="$HOME/.egregore/dashboard-id-$(echo -n "${MAIN_PROJECT_DIR:-$SCRIPT_DIR}" | cksum | cut -d' ' -f1).lock"
|
|
152
|
+
mkdir -p "$HOME/.egregore" 2>/dev/null
|
|
153
|
+
if ! mkdir "$_DB_LOCK" 2>/dev/null; then
|
|
154
|
+
_DB_LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$_DB_LOCK" 2>/dev/null || stat -c %Y "$_DB_LOCK" 2>/dev/null || echo 0) ))
|
|
155
|
+
# Stale reap by atomic rename, never rmdir+mkdir: two reapers doing
|
|
156
|
+
# remove-then-recreate can alternately delete each other's FRESH lock and
|
|
157
|
+
# both proceed. Directory rename is atomic — exactly one reaper's mv
|
|
158
|
+
# succeeds; the loser (and anyone losing the follow-up mkdir to a fresh
|
|
159
|
+
# contender) backs off to the read-only path.
|
|
160
|
+
if [ "$_DB_LOCK_AGE" -gt 300 ] && mv "$_DB_LOCK" "$_DB_LOCK.reap.$$" 2>/dev/null; then
|
|
161
|
+
rm -rf "$_DB_LOCK.reap.$$" 2>/dev/null
|
|
162
|
+
mkdir "$_DB_LOCK" 2>/dev/null || _DB_LOCK=""
|
|
163
|
+
else
|
|
164
|
+
_DB_LOCK=""
|
|
165
|
+
fi
|
|
166
|
+
fi
|
|
167
|
+
if [ -n "$_DB_LOCK" ]; then
|
|
168
|
+
# Re-read under the lock — the racing boot may have created the id already.
|
|
169
|
+
_DB_ID=$(jq -r '.dashboard_artifact_id // empty' "$_DB_STATE" 2>/dev/null)
|
|
170
|
+
if [ -z "$_DB_ID" ]; then
|
|
171
|
+
_DB_RAND=$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom 2>/dev/null | head -c 16)
|
|
172
|
+
[ -n "$_DB_RAND" ] || _DB_RAND=$(openssl rand -hex 8 2>/dev/null)
|
|
173
|
+
if [ -n "$_DB_RAND" ]; then
|
|
174
|
+
jq --arg id "dashboard-${_DB_RAND}" \
|
|
175
|
+
'.dashboard_artifact_id = (.dashboard_artifact_id // $id)' "$_DB_STATE" > "$_DB_STATE.tmp.$$" 2>/dev/null \
|
|
176
|
+
&& mv "$_DB_STATE.tmp.$$" "$_DB_STATE" 2>/dev/null || rm -f "$_DB_STATE.tmp.$$" 2>/dev/null
|
|
177
|
+
_DB_ID=$(jq -r '.dashboard_artifact_id // empty' "$_DB_STATE" 2>/dev/null)
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
rmdir "$_DB_LOCK" 2>/dev/null || true
|
|
181
|
+
else
|
|
182
|
+
# Lost the race — adopt whatever the winner persisted, if it landed yet.
|
|
183
|
+
_DB_ID=$(jq -r '.dashboard_artifact_id // empty' "$_DB_STATE" 2>/dev/null)
|
|
184
|
+
fi
|
|
185
|
+
fi
|
|
186
|
+
if [ "${LOCAL_MODE:-false}" != "true" ] && [ -n "$_DB_SLUG" ] && [ -n "$_DB_ID" ]; then
|
|
187
|
+
# Confirmation is BOUND TO THE ID: dashboard_published_id must equal the id
|
|
188
|
+
# we are about to advertise. A bare boolean could be set by a publish of a
|
|
189
|
+
# different id (racing first boots) or by publish-artifact's ephemeral-relay
|
|
190
|
+
# fallback returning some other https URL when the API key is missing —
|
|
191
|
+
# later boots would then advertise a stable URL nothing was published to.
|
|
192
|
+
_DB_EXPECTED_URL="https://egregore.xyz/view/${_DB_SLUG}/${_DB_ID}"
|
|
193
|
+
_DB_CONFIRMED_ID=$(jq -r '.dashboard_published_id // empty' "$_DB_STATE" 2>/dev/null)
|
|
194
|
+
if [ "$_DB_CONFIRMED_ID" = "$_DB_ID" ]; then
|
|
195
|
+
# An artifact is confirmed at this exact id — safe to print the URL
|
|
196
|
+
# immediately and refresh its content detached, off the boot path.
|
|
197
|
+
DASHBOARD_URL="$_DB_EXPECTED_URL"
|
|
198
|
+
( (
|
|
199
|
+
bash "$SCRIPT_DIR/bin/publish-artifact.sh" document "$_DB_MD" \
|
|
200
|
+
--id "$_DB_ID" \
|
|
201
|
+
--title "Session Dashboard" \
|
|
202
|
+
--author "${GREETING_NAME:-$AUTHOR}" >/dev/null 2>&1 || true
|
|
203
|
+
rm -f "$_DB_MD"
|
|
204
|
+
) >/dev/null 2>&1 & ) 2>/dev/null
|
|
205
|
+
else
|
|
206
|
+
# First publish for this id: synchronous, so the greeting never advertises
|
|
207
|
+
# a URL with nothing behind it (publishing disabled, missing key, renderer
|
|
208
|
+
# failure, API outage). Confirm only when the returned URL is actually the
|
|
209
|
+
# stable URL for THIS id — host-agnostic suffix match, so a relay/ephemeral
|
|
210
|
+
# URL is shown for this boot but never confirms the stable id.
|
|
211
|
+
_DB_PUBLISH_OUT=$(bash "$SCRIPT_DIR/bin/publish-artifact.sh" document "$_DB_MD" \
|
|
212
|
+
--id "$_DB_ID" \
|
|
213
|
+
--title "Session Dashboard" \
|
|
214
|
+
--author "${GREETING_NAME:-$AUTHOR}" 2>/dev/null || true)
|
|
215
|
+
DASHBOARD_URL=$(echo "$_DB_PUBLISH_OUT" | grep -o 'https://[^ ]*' | tail -1)
|
|
216
|
+
case "$DASHBOARD_URL" in
|
|
217
|
+
*/"${_DB_SLUG}/${_DB_ID}")
|
|
218
|
+
jq --arg id "$_DB_ID" '.dashboard_published_id = $id | del(.dashboard_published)' "$_DB_STATE" > "$_DB_STATE.tmp.$$" 2>/dev/null \
|
|
219
|
+
&& mv "$_DB_STATE.tmp.$$" "$_DB_STATE" 2>/dev/null || rm -f "$_DB_STATE.tmp.$$" 2>/dev/null
|
|
220
|
+
;;
|
|
221
|
+
esac
|
|
222
|
+
rm -f "$_DB_MD"
|
|
223
|
+
fi
|
|
224
|
+
else
|
|
225
|
+
# Local/OSS mode: no stable hosted URL to print early — keep the synchronous
|
|
226
|
+
# publish (ephemeral relay URL) with the local file:// render as fallback.
|
|
227
|
+
_DB_PUBLISH_OUT=$(bash "$SCRIPT_DIR/bin/publish-artifact.sh" document "$_DB_MD" \
|
|
228
|
+
--title "Session Dashboard" \
|
|
229
|
+
--author "${GREETING_NAME:-$AUTHOR}" 2>/dev/null || true)
|
|
230
|
+
DASHBOARD_URL=$(echo "$_DB_PUBLISH_OUT" | grep -o 'https://[^ ]*' | tail -1)
|
|
231
|
+
|
|
232
|
+
# Fallback: generate HTML locally and use file:// URL (offline, no API key, etc.)
|
|
233
|
+
if [ -z "$DASHBOARD_URL" ]; then
|
|
234
|
+
_DB_HTML="/tmp/egregore-artifacts/dashboard-${EGREGORE_SESSION_ID}.html"
|
|
235
|
+
mkdir -p /tmp/egregore-artifacts
|
|
236
|
+
if npx egregore-artifacts@latest document "$_DB_MD" --output "$_DB_HTML" --no-open >/dev/null 2>&1 && [ -f "$_DB_HTML" ]; then
|
|
237
|
+
DASHBOARD_URL="file://${_DB_HTML}"
|
|
238
|
+
fi
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
rm -f "$_DB_MD"
|
|
242
|
+
fi
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env 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
|