create-egregore 0.19.3 → 0.19.6
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 +410 -26
- package/bin/cli.js +34 -20
- package/lib/local.js +84 -11
- package/lib/pi-runtime.js +186 -0
- package/lib/setup.js +56 -11
- package/lib/ui.js +1 -1
- package/package.json +8 -6
- package/runtime/codex/.codex/hooks/search-hint.js +65 -0
- package/runtime/codex/.codex/hooks.json +13 -0
- package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +14 -10
- package/runtime/codex/.codex/skills/minion/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/scroll/SKILL.md +168 -0
- package/runtime/codex/.codex/skills/scroll/agents/openai.yaml +4 -0
- package/runtime/codex/.codex/skills/scroll/assets/shell.html +542 -0
- package/runtime/codex/.codex/skills/search/SKILL.md +56 -0
- package/runtime/codex/.codex/skills/session-view/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/thread/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/view/SKILL.md +147 -32
- package/runtime/codex/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/codex/.codex/spec-manifest.json +4 -4
- package/runtime/codex/AGENTS.md +31 -5
- package/runtime/codex/bin/activity-data.sh +46 -4
- package/runtime/codex/bin/agent.sh +10 -2
- package/runtime/codex/bin/codex-install-skills.sh +1 -1
- package/runtime/codex/bin/codex-render-spec.mjs +24 -2
- package/runtime/codex/bin/codex-session-start.sh +6 -60
- package/runtime/codex/bin/codex-skill-render.mjs +20 -12
- package/runtime/codex/bin/codex-sync-skills.sh +4 -0
- package/runtime/codex/bin/graph-op.sh +56 -5
- package/runtime/codex/bin/graph.sh +36 -0
- package/runtime/codex/bin/handoff-run.sh +157 -7
- package/runtime/codex/bin/handoff-save-egregore.sh +6 -1
- package/runtime/codex/bin/index-handoff.sh +9 -3
- package/runtime/codex/bin/lib/context.sh +97 -18
- package/runtime/codex/bin/lib/dashboard-artifact.sh +1 -1
- package/runtime/codex/bin/lib/git-sync.sh +35 -9
- package/runtime/codex/bin/lib/greeting.sh +30 -104
- package/runtime/codex/bin/lib/metrics.sh +374 -0
- package/runtime/codex/bin/publish-artifact.sh +43 -1
- package/runtime/codex/bin/settings.sh +274 -0
- package/runtime/codex/manifest.json +18 -1
- package/runtime/pi/.codex/config.toml +15 -0
- package/runtime/pi/.codex/hooks/branch-guard.js +242 -0
- package/runtime/pi/.codex/hooks/search-hint.js +65 -0
- package/runtime/pi/.codex/hooks.json +30 -0
- package/runtime/pi/.codex/skills/activity/SKILL.md +70 -0
- package/runtime/pi/.codex/skills/add/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/announce/SKILL.md +54 -0
- package/runtime/pi/.codex/skills/answer/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/archive/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/ask/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/branch/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/checkup/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/commit/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/contribute/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dark-mode/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +74 -0
- package/runtime/pi/.codex/skills/delete-user/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/emissary/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/env/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/handoff/SKILL.md +67 -0
- package/runtime/pi/.codex/skills/harvest/SKILL.md +107 -0
- package/runtime/pi/.codex/skills/ingest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-google/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/invite/SKILL.md +40 -0
- package/runtime/pi/.codex/skills/issue/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/me/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/meeting/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/minion/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/note/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/onboarding/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pr/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/project/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pull/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/push/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/quest/SKILL.md +77 -0
- package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/reflect/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/review-pr/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/save/SKILL.md +62 -0
- package/runtime/pi/.codex/skills/scroll/SKILL.md +168 -0
- package/runtime/pi/.codex/skills/scroll/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/scroll/assets/shell.html +542 -0
- package/runtime/pi/.codex/skills/search/SKILL.md +56 -0
- package/runtime/pi/.codex/skills/session-view/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/setup/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/summon/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/sync-repos/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telemetry/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/test/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/pi/.codex/skills/thread/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/todo/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tui-design/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tutorial/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/update/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/view/SKILL.md +156 -0
- package/runtime/pi/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/pi/.codex/skills/visual-explain/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/wrap/SKILL.md +55 -0
- package/runtime/pi/.codex/spec-manifest.json +114 -0
- package/runtime/pi/.pi/APPEND_SYSTEM.md +255 -0
- package/runtime/pi/.pi/extensions/egregore.ts +324 -0
- package/runtime/pi/.pi/settings.json +6 -0
- package/runtime/pi/.pi/spec-manifest.json +12 -0
- package/runtime/pi/AGENTS.md +350 -0
- package/runtime/pi/bin/activity-data.sh +242 -0
- package/runtime/pi/bin/agent.sh +677 -0
- package/runtime/pi/bin/codex-install-skills.sh +78 -0
- package/runtime/pi/bin/codex-render-spec.mjs +394 -0
- package/runtime/pi/bin/codex-session-start.sh +188 -0
- package/runtime/pi/bin/codex-skill-render.mjs +323 -0
- package/runtime/pi/bin/codex-sync-skills.sh +227 -0
- package/runtime/pi/bin/dashboard-data.sh +178 -0
- package/runtime/pi/bin/graph-batch.sh +60 -0
- package/runtime/pi/bin/graph-op.sh +431 -0
- package/runtime/pi/bin/graph-wal.sh +228 -0
- package/runtime/pi/bin/graph.sh +177 -0
- package/runtime/pi/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/pi/bin/handoff-run.sh +581 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +136 -0
- package/runtime/pi/bin/index-handoff.sh +312 -0
- package/runtime/pi/bin/lib/artifact-id.sh +46 -0
- package/runtime/pi/bin/lib/config.sh +71 -0
- package/runtime/pi/bin/lib/context.sh +542 -0
- package/runtime/pi/bin/lib/dashboard-artifact.sh +142 -0
- package/runtime/pi/bin/lib/ensure-develop.sh +183 -0
- package/runtime/pi/bin/lib/git-sync.sh +288 -0
- package/runtime/pi/bin/lib/greeting.sh +340 -0
- package/runtime/pi/bin/lib/hash.sh +13 -0
- package/runtime/pi/bin/lib/identity.sh +174 -0
- package/runtime/pi/bin/lib/metrics.sh +374 -0
- package/runtime/pi/bin/lib/permissions.sh +106 -0
- package/runtime/pi/bin/lib/time.sh +56 -0
- package/runtime/pi/bin/lib/worktree-links.sh +54 -0
- package/runtime/pi/bin/notify.sh +207 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +15 -0
- package/runtime/pi/bin/pi-product-workflows.mjs +324 -0
- package/runtime/pi/bin/pi-render-spec.mjs +114 -0
- package/runtime/pi/bin/pi-session-start.sh +24 -0
- package/runtime/pi/bin/publish-artifact.sh +201 -0
- package/runtime/pi/bin/publish-references.sh +144 -0
- package/runtime/pi/bin/repo-state.sh +99 -0
- package/runtime/pi/bin/telemetry.sh +391 -0
- package/runtime/pi/bin/worktree-create.sh +118 -0
- package/runtime/pi/bin/worktree-remove.sh +50 -0
- package/runtime/pi/bin/worktree.sh +198 -0
- package/runtime/pi/manifest.json +176 -0
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
# Renders the full session greeting:
|
|
5
5
|
# - ASCII art banner
|
|
6
6
|
# - Identity line (org/repo + user + branch)
|
|
7
|
-
# -
|
|
8
|
-
# -
|
|
9
|
-
# - "Merged" section (PRs, implemented handoffs)
|
|
7
|
+
# - Momentum board (sessions, commits, handoffs, knowledge)
|
|
8
|
+
# - Pending questions signal
|
|
10
9
|
# - Health footer
|
|
11
10
|
# - Alias migration
|
|
12
11
|
# - Session context JSON (hidden, for Claude)
|
|
@@ -64,108 +63,24 @@ if [ "$ID_PADDING" -lt 1 ]; then ID_PADDING=1; fi
|
|
|
64
63
|
printf "\n%s%*s%s\n" "$IDENTITY_LEFT" "$ID_PADDING" "" "$IDENTITY_RIGHT"
|
|
65
64
|
echo "$SEPARATOR"
|
|
66
65
|
|
|
67
|
-
# ---
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# --- Section 1: For you (always present) ---
|
|
81
|
-
echo " ◦ for you"
|
|
82
|
-
ADDRESSED_RICH=$(cat "$CTX_DIR/addressed_rich" 2>/dev/null || echo "[]")
|
|
83
|
-
ADDRESSED_COUNT=$(echo "$ADDRESSED_RICH" | jq 'length' 2>/dev/null || echo "0")
|
|
84
|
-
|
|
85
|
-
# Handoffs addressed to you
|
|
86
|
-
if [ "$ADDRESSED_COUNT" -gt 0 ] 2>/dev/null && [ "$ADDRESSED_COUNT" != "0" ]; then
|
|
87
|
-
echo "$ADDRESSED_RICH" | jq -r '.[] | "\(.author)\t\(.date)\t\(.topic)"' 2>/dev/null | while IFS=$'\t' read -r H_AUTHOR H_DATE H_TOPIC; do
|
|
88
|
-
[ -z "$H_AUTHOR" ] && continue
|
|
89
|
-
# Convert date to epoch (UTC) and compute calendar-day diff
|
|
90
|
-
H_DATE_ONLY="${H_DATE%%T*}"
|
|
91
|
-
H_EVENT_MIDNIGHT=$(date -j -f "%Y-%m-%d" "$H_DATE_ONLY" +%s 2>/dev/null || \
|
|
92
|
-
date -d "$H_DATE_ONLY" +%s 2>/dev/null || echo "0")
|
|
93
|
-
H_CAL_DAYS=$(( (TODAY_MIDNIGHT - H_EVENT_MIDNIGHT) / 86400 ))
|
|
94
|
-
# Skip if older than recency threshold
|
|
95
|
-
[ "$H_CAL_DAYS" -gt "$RECENCY_DAYS" ] 2>/dev/null && continue
|
|
96
|
-
H_NAME=$(echo "$H_AUTHOR" | awk '{print tolower($1)}')
|
|
97
|
-
if [ ${#H_NAME} -gt 8 ]; then H_NAME="${H_NAME:0:8}"; fi
|
|
98
|
-
# Online status from team presence data
|
|
99
|
-
H_SEEN_EPOCH=$(echo "$TEAM_DATA" | jq -r --arg n "$H_NAME" '[.[] | select((.name | ascii_downcase) == $n) | .last_seen_sort] | .[0] // 0' 2>/dev/null || echo "0")
|
|
100
|
-
if [ "$H_SEEN_EPOCH" -gt 0 ] 2>/dev/null && [ $(( NOW_RENDER - H_SEEN_EPOCH )) -lt $ONLINE_THRESHOLD ] 2>/dev/null; then
|
|
101
|
-
DOT="●"
|
|
102
|
-
else
|
|
103
|
-
DOT="○"
|
|
104
|
-
fi
|
|
105
|
-
# Calendar-day relative label
|
|
106
|
-
if [ "$H_CAL_DAYS" -le 0 ] 2>/dev/null; then H_AGO="today"
|
|
107
|
-
elif [ "$H_CAL_DAYS" -eq 1 ] 2>/dev/null; then H_AGO="yesterday"
|
|
108
|
-
else H_AGO="${H_CAL_DAYS}d ago"
|
|
109
|
-
fi
|
|
110
|
-
if [ ${#H_TOPIC} -gt $MAX_INFO ]; then H_TOPIC="${H_TOPIC:0:$((MAX_INFO - 1))}…"; fi
|
|
111
|
-
printf " %s %-9s%-12s%s\n" "$DOT" "$H_NAME" "$H_AGO" "$H_TOPIC"
|
|
112
|
-
done
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
# Fallback: last activity if no handoffs
|
|
116
|
-
if [ "$ADDRESSED_COUNT" = "0" ] || [ -z "$ADDRESSED_COUNT" ]; then
|
|
117
|
-
LAST_ACTIVITY=$(cat "$CTX_DIR/activity" 2>/dev/null || echo "")
|
|
118
|
-
if [ -n "$LAST_ACTIVITY" ]; then
|
|
119
|
-
LA_TIME=$(echo "$LAST_ACTIVITY" | cut -d'|' -f1)
|
|
120
|
-
# Compact relative time: "20 hours ago" → "20h ago", "3 days ago" → "3d ago"
|
|
121
|
-
LA_TIME=$(echo "$LA_TIME" | sed 's/ hours\{0,1\} ago/h ago/; s/ days\{0,1\} ago/d ago/; s/ minutes\{0,1\} ago/m ago/; s/ weeks\{0,1\} ago/w ago/; s/ months\{0,1\} ago/mo ago/')
|
|
122
|
-
LA_MSG=$(echo "$LAST_ACTIVITY" | cut -d'|' -f2-)
|
|
123
|
-
if [ ${#LA_MSG} -gt $MAX_INFO ]; then LA_MSG="${LA_MSG:0:$((MAX_INFO - 1))}…"; fi
|
|
124
|
-
printf " ◇ %-9s%-12s%s\n" "you" "$LA_TIME" "$LA_MSG"
|
|
125
|
-
fi
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
echo ""
|
|
129
|
-
# --- Section 2: Around (team presence with online status) ---
|
|
130
|
-
if [ "$TEAM_DATA_COUNT" -gt 0 ] 2>/dev/null && [ "$TEAM_DATA_COUNT" != "0" ]; then
|
|
131
|
-
echo " ◦ around"
|
|
132
|
-
# Presence roster with online/offline dots (hide inactive >3 days)
|
|
133
|
-
STALE_THRESHOLD=$((RECENCY_DAYS * 86400))
|
|
134
|
-
echo "$TEAM_DATA" | jq -r '.[] | "\(.name)\t\(.last_seen_sort)\t\(.last_seen)\t\(.branches | join(", "))"' 2>/dev/null | while IFS=$'\t' read -r P_NAME P_EPOCH P_SEEN P_BRANCHES; do
|
|
135
|
-
[ -z "$P_NAME" ] && continue
|
|
136
|
-
# Skip if no recent activity (within recency window)
|
|
137
|
-
if [ "$P_EPOCH" -le 0 ] 2>/dev/null; then
|
|
138
|
-
continue
|
|
139
|
-
elif [ $(( NOW_RENDER - P_EPOCH )) -ge $STALE_THRESHOLD ] 2>/dev/null; then
|
|
140
|
-
continue
|
|
141
|
-
fi
|
|
142
|
-
if [ ${#P_NAME} -gt 8 ]; then P_NAME="${P_NAME:0:8}"; fi
|
|
143
|
-
# Online: last seen within threshold
|
|
144
|
-
if [ $(( NOW_RENDER - P_EPOCH )) -lt $ONLINE_THRESHOLD ] 2>/dev/null; then
|
|
145
|
-
DOT="●"
|
|
146
|
-
else
|
|
147
|
-
DOT="○"
|
|
148
|
-
fi
|
|
149
|
-
if [ ${#P_BRANCHES} -gt $MAX_INFO ]; then
|
|
150
|
-
P_BRANCHES="${P_BRANCHES:0:$((MAX_INFO - 9))}... +more"
|
|
151
|
-
fi
|
|
152
|
-
printf " %s %-9s%-12s%s\n" "$DOT" "$P_NAME" "$P_SEEN" "$P_BRANCHES"
|
|
153
|
-
done
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
# --- Section 3: Recently merged PRs + implemented handoffs ---
|
|
157
|
-
LIFECYCLE_JSON=$(cat "$CTX_DIR/lifecycle" 2>/dev/null || echo '{}')
|
|
158
|
-
MERGED_COUNT=$(echo "$LIFECYCLE_JSON" | jq '.merged_prs.values // [] | length' 2>/dev/null || echo "0")
|
|
159
|
-
IMPL_COUNT=$(echo "$LIFECYCLE_JSON" | jq '.implemented_handoffs.values // [] | length' 2>/dev/null || echo "0")
|
|
160
|
-
|
|
161
|
-
if [ "$MERGED_COUNT" -gt 0 ] 2>/dev/null || [ "$IMPL_COUNT" -gt 0 ] 2>/dev/null; then
|
|
162
|
-
echo ""
|
|
163
|
-
echo " ◦ merged"
|
|
164
|
-
if [ "$MERGED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
165
|
-
echo "$LIFECYCLE_JSON" | jq -r '.merged_prs.values[]? // empty | " ✓ PR #\(.[0]) \(.[1])"' 2>/dev/null || true
|
|
66
|
+
# --- Momentum board ---
|
|
67
|
+
source "$SCRIPT_DIR/bin/lib/metrics.sh"
|
|
68
|
+
_render_momentum_board
|
|
69
|
+
|
|
70
|
+
# Pending questions addressed to you (one summary line — /answer to engage)
|
|
71
|
+
PENDING_Q=$(cat "$CTX_DIR/pending_questions" 2>/dev/null || echo "[]")
|
|
72
|
+
PENDING_Q_COUNT=$(echo "$PENDING_Q" | jq 'length' 2>/dev/null || echo "0")
|
|
73
|
+
if [ "$PENDING_Q_COUNT" -gt 0 ] 2>/dev/null && [ "$PENDING_Q_COUNT" != "0" ]; then
|
|
74
|
+
PQ_SENDERS=$(echo "$PENDING_Q" | jq -r '[.[].from] | unique | join(", ")' 2>/dev/null)
|
|
75
|
+
if [ "$PENDING_Q_COUNT" = "1" ]; then
|
|
76
|
+
PQ_NOUN="question"
|
|
77
|
+
else
|
|
78
|
+
PQ_NOUN="questions"
|
|
166
79
|
fi
|
|
167
|
-
if [ "$
|
|
168
|
-
|
|
80
|
+
if [ -n "$PQ_SENDERS" ]; then
|
|
81
|
+
printf " ◐ %s pending %s from %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN" "$PQ_SENDERS"
|
|
82
|
+
else
|
|
83
|
+
printf " ◐ %s pending %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN"
|
|
169
84
|
fi
|
|
170
85
|
fi
|
|
171
86
|
|
|
@@ -256,6 +171,10 @@ if [ -n "${BOARD_URL:-}" ]; then
|
|
|
256
171
|
printf " ◆ %s (board)\n" "$BOARD_URL"
|
|
257
172
|
fi
|
|
258
173
|
|
|
174
|
+
if [ -n "${LOOM_DOCTOR_BRIEF:-}" ]; then
|
|
175
|
+
printf " %s\n" "$LOOM_DOCTOR_BRIEF"
|
|
176
|
+
fi
|
|
177
|
+
|
|
259
178
|
# Framework updates come through PRs to develop — no separate auto-update channel.
|
|
260
179
|
# The develop sync above already keeps framework files current.
|
|
261
180
|
# Use /update for manual upstream pulls when needed.
|
|
@@ -288,6 +207,12 @@ CONTEXT_TEAM=$(cat "$CTX_DIR/team" 2>/dev/null || echo "[]")
|
|
|
288
207
|
CONTEXT_SOUL=$(cat "$CTX_DIR/soul_summary" 2>/dev/null || echo "")
|
|
289
208
|
CONTEXT_LIFECYCLE=$(cat "$CTX_DIR/lifecycle" 2>/dev/null || echo '{"merged_prs":[],"implemented_handoffs":[]}')
|
|
290
209
|
CONTEXT_PULSE=$(cat "$CTX_DIR/pulse_brief" 2>/dev/null || echo '{}')
|
|
210
|
+
if [ -f "$CTX_DIR/metrics" ]; then
|
|
211
|
+
CONTEXT_METRICS=$(jq -c . "$CTX_DIR/metrics" 2>/dev/null || echo "{}")
|
|
212
|
+
[ -n "$CONTEXT_METRICS" ] || CONTEXT_METRICS="{}"
|
|
213
|
+
else
|
|
214
|
+
CONTEXT_METRICS="{}"
|
|
215
|
+
fi
|
|
291
216
|
|
|
292
217
|
# --- Write compact subagent context cache (reuses already-gathered data) ---
|
|
293
218
|
SUBAGENT_CTX="/tmp/egregore-subagent-ctx-${EGREGORE_SESSION_ID}.txt"
|
|
@@ -332,6 +257,7 @@ cat << CTXEOF
|
|
|
332
257
|
"team_recent_memory": $CONTEXT_TEAM,
|
|
333
258
|
"soul_self_summary": "$CONTEXT_SOUL",
|
|
334
259
|
"lifecycle": $CONTEXT_LIFECYCLE,
|
|
260
|
+
"momentum": $CONTEXT_METRICS,
|
|
335
261
|
"pulse": $CONTEXT_PULSE
|
|
336
262
|
}
|
|
337
263
|
-->
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# metrics.sh — Momentum metrics gathering and rendering for startup greetings.
|
|
3
|
+
#
|
|
4
|
+
# Function-only library. Safe to source from bash or zsh.
|
|
5
|
+
|
|
6
|
+
_metrics_zero_json() {
|
|
7
|
+
printf '%s\n' '{"source":"local","sessions":{"buckets":[0,0,0,0,0],"week":0,"prev":0,"all":0},"commits":{"buckets":[0,0,0,0,0],"week":0,"prev":0,"authors":0,"all":0},"handoffs":{"buckets":[0,0,0,0,0],"week":0,"prev":0,"avg_resolution_days":null,"all":0},"knowledge":{"buckets":[0,0,0,0,0],"week":0,"prev":0,"all":0},"members":{"active":0,"total":0}}'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_num() {
|
|
11
|
+
awk '{n=$1+0; if (n < 0) n=0; printf "%d\n", n}' 2>/dev/null <<EOF
|
|
12
|
+
$1
|
|
13
|
+
EOF
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_num_float() {
|
|
17
|
+
awk '{n=$1+0; if (n < 0) n=0; printf "%.1f\n", n}' 2>/dev/null <<EOF
|
|
18
|
+
$1
|
|
19
|
+
EOF
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_normalize_buckets() {
|
|
23
|
+
set -- $(printf '%s' "$1")
|
|
24
|
+
printf '%d %d %d %d %d\n' "$(_num "${1:-0}")" "$(_num "${2:-0}")" "$(_num "${3:-0}")" "$(_num "${4:-0}")" "$(_num "${5:-0}")"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_buckets_json() {
|
|
28
|
+
set -- $(printf '%s' "$(_normalize_buckets "$1")")
|
|
29
|
+
jq -n --argjson a "$(_num "${1:-0}")" --argjson b "$(_num "${2:-0}")" \
|
|
30
|
+
--argjson c "$(_num "${3:-0}")" --argjson d "$(_num "${4:-0}")" \
|
|
31
|
+
--argjson e "$(_num "${5:-0}")" '[$a,$b,$c,$d,$e]' 2>/dev/null || echo '[0,0,0,0,0]'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_bucket_week() {
|
|
35
|
+
set -- $(printf '%s' "$(_normalize_buckets "$1")")
|
|
36
|
+
_num "${5:-0}"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_bucket_prev() {
|
|
40
|
+
set -- $(printf '%s' "$(_normalize_buckets "$1")")
|
|
41
|
+
_num "${4:-0}"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_spark() {
|
|
45
|
+
local values max out v idx glyph
|
|
46
|
+
values="${1:-0 0 0 0 0}"
|
|
47
|
+
max=0
|
|
48
|
+
set -- $(printf '%s' "$values")
|
|
49
|
+
[ "$#" -eq 0 ] && set -- 0 0 0 0 0
|
|
50
|
+
for v in "$@"; do
|
|
51
|
+
v=$(_num "$v")
|
|
52
|
+
[ "$v" -gt "$max" ] 2>/dev/null && max="$v"
|
|
53
|
+
done
|
|
54
|
+
out=""
|
|
55
|
+
for v in "$@"; do
|
|
56
|
+
v=$(_num "$v")
|
|
57
|
+
if [ "$max" -le 0 ] 2>/dev/null; then
|
|
58
|
+
idx=0
|
|
59
|
+
else
|
|
60
|
+
idx=$(( (v * 7) / max ))
|
|
61
|
+
fi
|
|
62
|
+
# Select glyphs explicitly: substring slicing can split UTF-8 characters
|
|
63
|
+
# under Bash 3.2 or a C locale.
|
|
64
|
+
case "$idx" in
|
|
65
|
+
0) glyph="▁" ;;
|
|
66
|
+
1) glyph="▂" ;;
|
|
67
|
+
2) glyph="▃" ;;
|
|
68
|
+
3) glyph="▄" ;;
|
|
69
|
+
4) glyph="▅" ;;
|
|
70
|
+
5) glyph="▆" ;;
|
|
71
|
+
6) glyph="▇" ;;
|
|
72
|
+
*) glyph="█" ;;
|
|
73
|
+
esac
|
|
74
|
+
out="${out}${glyph}"
|
|
75
|
+
done
|
|
76
|
+
printf '%s\n' "$out"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_pct_delta() {
|
|
80
|
+
local cur prev pct
|
|
81
|
+
cur=$(_num "${1:-0}")
|
|
82
|
+
prev=$(_num "${2:-0}")
|
|
83
|
+
[ "$prev" -le 0 ] 2>/dev/null && return 0
|
|
84
|
+
pct=$(( ((cur - prev) * 100) / prev ))
|
|
85
|
+
if [ "$pct" -gt 0 ] 2>/dev/null; then
|
|
86
|
+
printf '↑ %d%%\n' "$pct"
|
|
87
|
+
elif [ "$pct" -lt 0 ] 2>/dev/null; then
|
|
88
|
+
printf '↓ %d%%\n' "$(( -pct ))"
|
|
89
|
+
else
|
|
90
|
+
printf '→ 0%%\n'
|
|
91
|
+
fi
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_commafy() {
|
|
95
|
+
awk '
|
|
96
|
+
function comma(s, out, sign) {
|
|
97
|
+
s = int(s + 0)
|
|
98
|
+
if (s < 0) { sign = "-"; s = -s } else { sign = "" }
|
|
99
|
+
s = sprintf("%d", s)
|
|
100
|
+
out = ""
|
|
101
|
+
while (length(s) > 3) {
|
|
102
|
+
out = "," substr(s, length(s) - 2, 3) out
|
|
103
|
+
s = substr(s, 1, length(s) - 3)
|
|
104
|
+
}
|
|
105
|
+
return sign s out
|
|
106
|
+
}
|
|
107
|
+
{ print comma($1) }
|
|
108
|
+
' 2>/dev/null <<EOF
|
|
109
|
+
${1:-0}
|
|
110
|
+
EOF
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_git_added_buckets() {
|
|
114
|
+
local repo now paths
|
|
115
|
+
repo="$1"
|
|
116
|
+
shift
|
|
117
|
+
now=$(date +%s)
|
|
118
|
+
if [ -d "$repo" ] || [ -f "$repo" ]; then
|
|
119
|
+
git -C "$repo" log --diff-filter=A --since="35 days ago" --format='%ct' -- "$@" 2>/dev/null | \
|
|
120
|
+
awk -v now="$now" '
|
|
121
|
+
BEGIN { for (i=0;i<5;i++) b[i]=0 }
|
|
122
|
+
/^[0-9]+$/ {
|
|
123
|
+
days = int((now - $1) / 86400)
|
|
124
|
+
idx = 4 - int(days / 7)
|
|
125
|
+
if (idx >= 0 && idx < 5) b[idx]++
|
|
126
|
+
}
|
|
127
|
+
END { printf "%d %d %d %d %d\n", b[0], b[1], b[2], b[3], b[4] }
|
|
128
|
+
' 2>/dev/null || echo "0 0 0 0 0"
|
|
129
|
+
else
|
|
130
|
+
echo "0 0 0 0 0"
|
|
131
|
+
fi
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_find_count_md() {
|
|
135
|
+
find -L "$@" -name '*.md' ! -name 'index*' 2>/dev/null | wc -l | awk '{print $1+0}' 2>/dev/null || echo 0
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_metrics_gather() {
|
|
139
|
+
local _root _mem _scratch _API_URL _API_KEY _connected
|
|
140
|
+
_root="${SCRIPT_DIR:-$PWD}"
|
|
141
|
+
_mem="$_root/memory"
|
|
142
|
+
_scratch=$(mktemp -d 2>/dev/null || mktemp -d -t egregore-metrics)
|
|
143
|
+
_API_URL=$(jq -r '.api_url // empty' "$_root/egregore.json" 2>/dev/null || echo "")
|
|
144
|
+
_API_KEY=$(grep '^EGREGORE_API_KEY=' "${ENV_FILE:-$_root/.env}" 2>/dev/null | cut -d'=' -f2- || true)
|
|
145
|
+
_connected=false
|
|
146
|
+
[ -n "$_API_URL" ] && [ -n "$_API_KEY" ] && _connected=true
|
|
147
|
+
|
|
148
|
+
(
|
|
149
|
+
if [ "$_connected" = true ]; then
|
|
150
|
+
raw=$(bash "$_root/bin/graph.sh" query "MATCH (s:Session) WHERE date(s.date) >= date() - duration('P35D')
|
|
151
|
+
OPTIONAL MATCH (s)-[:BY]->(p:Person)
|
|
152
|
+
WITH duration.inDays(date(s.date), date()).days / 7 AS weeksAgo,
|
|
153
|
+
count(s) AS sessions, count(DISTINCT p) AS people
|
|
154
|
+
RETURN weeksAgo, sessions, people ORDER BY weeksAgo" 2>/dev/null || echo "")
|
|
155
|
+
printf '%s' "$raw" | jq -r '
|
|
156
|
+
(.values // []) as $v
|
|
157
|
+
| if ($v|length) == 0 then empty else
|
|
158
|
+
reduce $v[] as $r ({b:[0,0,0,0,0], a:0, ok:0};
|
|
159
|
+
($r[0] // 99 | tonumber? // 99) as $w
|
|
160
|
+
| if $w >= 0 and $w <= 4 then
|
|
161
|
+
.b[4 - $w] = (($r[1] // 0 | tonumber? // 0) | floor)
|
|
162
|
+
| .ok = 1
|
|
163
|
+
| if $w == 0 then .a = (($r[2] // 0 | tonumber? // 0) | floor) else . end
|
|
164
|
+
else . end)
|
|
165
|
+
| "\(.b|join(" "))|\(.a)|\(.ok)"
|
|
166
|
+
end
|
|
167
|
+
' 2>/dev/null || echo "0 0 0 0 0|0|0"
|
|
168
|
+
else
|
|
169
|
+
echo "0 0 0 0 0|0|0"
|
|
170
|
+
fi
|
|
171
|
+
) > "$_scratch/graph_sessions" 2>/dev/null &
|
|
172
|
+
|
|
173
|
+
(
|
|
174
|
+
if [ "$_connected" = true ]; then
|
|
175
|
+
raw=$(bash "$_root/bin/graph.sh" query "MATCH (s:Session) WITH count(s) AS totalSessions MATCH (p:Person)-[:MEMBER_OF]->(:Org) RETURN totalSessions, count(DISTINCT p) AS members" 2>/dev/null || echo "")
|
|
176
|
+
total=$(printf '%s' "$raw" | jq -r '.values[0][0] // 0' 2>/dev/null || echo 0)
|
|
177
|
+
members=$(printf '%s' "$raw" | jq -r '.values[0][1] // 0' 2>/dev/null || echo 0)
|
|
178
|
+
if [ "$(_num "$members")" -eq 0 ] 2>/dev/null; then
|
|
179
|
+
raw2=$(bash "$_root/bin/graph.sh" query "MATCH (p:Person) RETURN count(p)" 2>/dev/null || echo "")
|
|
180
|
+
members=$(printf '%s' "$raw2" | jq -r '.values[0][0] // 0' 2>/dev/null || echo 0)
|
|
181
|
+
fi
|
|
182
|
+
printf '%s|%s\n' "$(_num "$total")" "$(_num "$members")"
|
|
183
|
+
else
|
|
184
|
+
echo "0|0"
|
|
185
|
+
fi
|
|
186
|
+
) > "$_scratch/graph_totals" 2>/dev/null &
|
|
187
|
+
|
|
188
|
+
(
|
|
189
|
+
if [ "$_connected" = true ]; then
|
|
190
|
+
raw=$(bash "$_root/bin/graph.sh" query "MATCH (s:Session)-[:HANDED_TO]->(:Person)
|
|
191
|
+
WHERE s.handoffStatus = 'done' AND date(s.date) >= date() - duration('P30D')
|
|
192
|
+
AND s.handoffReadDate IS NOT NULL
|
|
193
|
+
WITH duration.inDays(date(s.date), date(s.handoffReadDate)).days AS d
|
|
194
|
+
RETURN avg(d) AS avgDays, count(*) AS n" 2>/dev/null || echo "")
|
|
195
|
+
avg=$(printf '%s' "$raw" | jq -r '.values[0][0] // empty' 2>/dev/null || echo "")
|
|
196
|
+
n=$(printf '%s' "$raw" | jq -r '.values[0][1] // 0' 2>/dev/null || echo 0)
|
|
197
|
+
if [ "$(_num "$n")" -gt 0 ] 2>/dev/null && [ -n "$avg" ]; then _num_float "$avg"; else echo ""; fi
|
|
198
|
+
else
|
|
199
|
+
echo ""
|
|
200
|
+
fi
|
|
201
|
+
) > "$_scratch/handoff_resolution" 2>/dev/null &
|
|
202
|
+
|
|
203
|
+
(
|
|
204
|
+
buckets=$(_git_added_buckets "$_mem" sessions wraps)
|
|
205
|
+
all=$(_find_count_md "$_root/memory/sessions" "$_root/memory/wraps")
|
|
206
|
+
printf '%s|%s\n' "$buckets" "$all"
|
|
207
|
+
) > "$_scratch/local_sessions" 2>/dev/null &
|
|
208
|
+
|
|
209
|
+
(
|
|
210
|
+
now=$(date +%s)
|
|
211
|
+
if [ -d "$_mem" ] || [ -f "$_mem" ]; then
|
|
212
|
+
git -C "$_mem" log --since="35 days ago" --format='%ct|%ae' 2>/dev/null | \
|
|
213
|
+
awk -F'|' -v now="$now" '
|
|
214
|
+
BEGIN { for (i=0;i<5;i++) b[i]=0 }
|
|
215
|
+
{
|
|
216
|
+
days = int((now - $1) / 86400)
|
|
217
|
+
idx = 4 - int(days / 7)
|
|
218
|
+
if (idx >= 0 && idx < 5) {
|
|
219
|
+
b[idx]++
|
|
220
|
+
if (idx == 4 && $2 != "") a[$2]=1
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
END {
|
|
224
|
+
n=0; for (k in a) n++
|
|
225
|
+
printf "%d %d %d %d %d|%d\n", b[0], b[1], b[2], b[3], b[4], n
|
|
226
|
+
}
|
|
227
|
+
' 2>/dev/null || echo "0 0 0 0 0|0"
|
|
228
|
+
else
|
|
229
|
+
echo "0 0 0 0 0|0"
|
|
230
|
+
fi
|
|
231
|
+
) > "$_scratch/commits" 2>/dev/null &
|
|
232
|
+
|
|
233
|
+
(
|
|
234
|
+
if [ -d "$_mem" ] || [ -f "$_mem" ]; then git -C "$_mem" rev-list --count HEAD 2>/dev/null || echo 0; else echo 0; fi
|
|
235
|
+
) > "$_scratch/commits_all" 2>/dev/null &
|
|
236
|
+
|
|
237
|
+
(
|
|
238
|
+
buckets=$(_git_added_buckets "$_mem" handoffs)
|
|
239
|
+
all=$(_find_count_md "$_root/memory/handoffs")
|
|
240
|
+
printf '%s|%s\n' "$buckets" "$all"
|
|
241
|
+
) > "$_scratch/handoffs" 2>/dev/null &
|
|
242
|
+
|
|
243
|
+
(
|
|
244
|
+
buckets=$(_git_added_buckets "$_mem" knowledge/decisions knowledge/findings knowledge/patterns)
|
|
245
|
+
all=$(_find_count_md "$_root/memory/knowledge/decisions" "$_root/memory/knowledge/findings" "$_root/memory/knowledge/patterns")
|
|
246
|
+
printf '%s|%s\n' "$buckets" "$all"
|
|
247
|
+
) > "$_scratch/knowledge" 2>/dev/null &
|
|
248
|
+
|
|
249
|
+
(
|
|
250
|
+
_find_count_md "$_root/memory/people"
|
|
251
|
+
) > "$_scratch/members_total_local" 2>/dev/null &
|
|
252
|
+
|
|
253
|
+
wait
|
|
254
|
+
|
|
255
|
+
gs=$(cat "$_scratch/graph_sessions" 2>/dev/null || echo "0 0 0 0 0|0|0")
|
|
256
|
+
gt=$(cat "$_scratch/graph_totals" 2>/dev/null || echo "0|0")
|
|
257
|
+
lsess=$(cat "$_scratch/local_sessions" 2>/dev/null || echo "0 0 0 0 0|0")
|
|
258
|
+
commits=$(cat "$_scratch/commits" 2>/dev/null || echo "0 0 0 0 0|0")
|
|
259
|
+
handoffs=$(cat "$_scratch/handoffs" 2>/dev/null || echo "0 0 0 0 0|0")
|
|
260
|
+
knowledge=$(cat "$_scratch/knowledge" 2>/dev/null || echo "0 0 0 0 0|0")
|
|
261
|
+
|
|
262
|
+
graph_valid=$(_num "$(printf '%s' "$gs" | awk -F'|' '{print $3}')")
|
|
263
|
+
if [ "$graph_valid" -gt 0 ] 2>/dev/null; then
|
|
264
|
+
source_name="graph"
|
|
265
|
+
session_buckets=$(_normalize_buckets "$(printf '%s' "$gs" | awk -F'|' '{print $1}')")
|
|
266
|
+
session_all=$(_num "$(printf '%s' "$gt" | awk -F'|' '{print $1}')")
|
|
267
|
+
members_active=$(_num "$(printf '%s' "$gs" | awk -F'|' '{print $2}')")
|
|
268
|
+
members_total=$(_num "$(printf '%s' "$gt" | awk -F'|' '{print $2}')")
|
|
269
|
+
if [ "$session_all" -le 0 ] 2>/dev/null; then
|
|
270
|
+
session_all=$(_num "$(printf '%s' "$lsess" | awk -F'|' '{print $2}')")
|
|
271
|
+
fi
|
|
272
|
+
if [ "$members_total" -le 0 ] 2>/dev/null; then
|
|
273
|
+
members_total=$(_num "$(cat "$_scratch/members_total_local" 2>/dev/null || echo 0)")
|
|
274
|
+
fi
|
|
275
|
+
else
|
|
276
|
+
source_name="local"
|
|
277
|
+
session_buckets=$(_normalize_buckets "$(printf '%s' "$lsess" | awk -F'|' '{print $1}')")
|
|
278
|
+
session_all=$(_num "$(printf '%s' "$lsess" | awk -F'|' '{print $2}')")
|
|
279
|
+
members_active=$(_num "$(printf '%s' "$commits" | awk -F'|' '{print $2}')")
|
|
280
|
+
members_total=$(_num "$(cat "$_scratch/members_total_local" 2>/dev/null || echo 0)")
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
commit_buckets=$(_normalize_buckets "$(printf '%s' "$commits" | awk -F'|' '{print $1}')")
|
|
284
|
+
handoff_buckets=$(_normalize_buckets "$(printf '%s' "$handoffs" | awk -F'|' '{print $1}')")
|
|
285
|
+
knowledge_buckets=$(_normalize_buckets "$(printf '%s' "$knowledge" | awk -F'|' '{print $1}')")
|
|
286
|
+
avg_res=$(cat "$_scratch/handoff_resolution" 2>/dev/null || echo "")
|
|
287
|
+
|
|
288
|
+
session_buckets_json=$(_buckets_json "$session_buckets")
|
|
289
|
+
commit_buckets_json=$(_buckets_json "$commit_buckets")
|
|
290
|
+
handoff_buckets_json=$(_buckets_json "$handoff_buckets")
|
|
291
|
+
knowledge_buckets_json=$(_buckets_json "$knowledge_buckets")
|
|
292
|
+
|
|
293
|
+
if [ -n "$avg_res" ]; then
|
|
294
|
+
jq -n --arg source "$source_name" \
|
|
295
|
+
--argjson sb "$session_buckets_json" --argjson sw "$(_bucket_week "$session_buckets")" --argjson sp "$(_bucket_prev "$session_buckets")" --argjson sall "$session_all" \
|
|
296
|
+
--argjson cb "$commit_buckets_json" --argjson cw "$(_bucket_week "$commit_buckets")" --argjson cp "$(_bucket_prev "$commit_buckets")" --argjson ca "$(_num "$(printf '%s' "$commits" | awk -F'|' '{print $2}')")" --argjson call "$(_num "$(cat "$_scratch/commits_all" 2>/dev/null || echo 0)")" \
|
|
297
|
+
--argjson hb "$handoff_buckets_json" --argjson hw "$(_bucket_week "$handoff_buckets")" --argjson hp "$(_bucket_prev "$handoff_buckets")" --argjson havg "$avg_res" --argjson hall "$(_num "$(printf '%s' "$handoffs" | awk -F'|' '{print $2}')")" \
|
|
298
|
+
--argjson kb "$knowledge_buckets_json" --argjson kw "$(_bucket_week "$knowledge_buckets")" --argjson kp "$(_bucket_prev "$knowledge_buckets")" --argjson kall "$(_num "$(printf '%s' "$knowledge" | awk -F'|' '{print $2}')")" \
|
|
299
|
+
--argjson ma "$members_active" --argjson mt "$members_total" \
|
|
300
|
+
'{source:$source,sessions:{buckets:$sb,week:$sw,prev:$sp,all:$sall},commits:{buckets:$cb,week:$cw,prev:$cp,authors:$ca,all:$call},handoffs:{buckets:$hb,week:$hw,prev:$hp,avg_resolution_days:$havg,all:$hall},knowledge:{buckets:$kb,week:$kw,prev:$kp,all:$kall},members:{active:$ma,total:$mt}}' 2>/dev/null || _metrics_zero_json
|
|
301
|
+
else
|
|
302
|
+
jq -n --arg source "$source_name" \
|
|
303
|
+
--argjson sb "$session_buckets_json" --argjson sw "$(_bucket_week "$session_buckets")" --argjson sp "$(_bucket_prev "$session_buckets")" --argjson sall "$session_all" \
|
|
304
|
+
--argjson cb "$commit_buckets_json" --argjson cw "$(_bucket_week "$commit_buckets")" --argjson cp "$(_bucket_prev "$commit_buckets")" --argjson ca "$(_num "$(printf '%s' "$commits" | awk -F'|' '{print $2}')")" --argjson call "$(_num "$(cat "$_scratch/commits_all" 2>/dev/null || echo 0)")" \
|
|
305
|
+
--argjson hb "$handoff_buckets_json" --argjson hw "$(_bucket_week "$handoff_buckets")" --argjson hp "$(_bucket_prev "$handoff_buckets")" --argjson hall "$(_num "$(printf '%s' "$handoffs" | awk -F'|' '{print $2}')")" \
|
|
306
|
+
--argjson kb "$knowledge_buckets_json" --argjson kw "$(_bucket_week "$knowledge_buckets")" --argjson kp "$(_bucket_prev "$knowledge_buckets")" --argjson kall "$(_num "$(printf '%s' "$knowledge" | awk -F'|' '{print $2}')")" \
|
|
307
|
+
--argjson ma "$members_active" --argjson mt "$members_total" \
|
|
308
|
+
'{source:$source,sessions:{buckets:$sb,week:$sw,prev:$sp,all:$sall},commits:{buckets:$cb,week:$cw,prev:$cp,authors:$ca,all:$call},handoffs:{buckets:$hb,week:$hw,prev:$hp,avg_resolution_days:null,all:$hall},knowledge:{buckets:$kb,week:$kw,prev:$kp,all:$kall},members:{active:$ma,total:$mt}}' 2>/dev/null || _metrics_zero_json
|
|
309
|
+
fi
|
|
310
|
+
rm -rf "$_scratch" 2>/dev/null || true
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
_metrics_read() {
|
|
314
|
+
local file filter fallback
|
|
315
|
+
file="${CTX_DIR:-}/metrics"
|
|
316
|
+
filter="$1"
|
|
317
|
+
fallback="$2"
|
|
318
|
+
if [ -f "$file" ]; then
|
|
319
|
+
jq -r "$filter" "$file" 2>/dev/null || echo "$fallback"
|
|
320
|
+
else
|
|
321
|
+
echo "$fallback"
|
|
322
|
+
fi
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
_render_momentum_board() {
|
|
326
|
+
local separator line_width header_left header_right pad
|
|
327
|
+
local sb sw sp sall cb cw ca call hb hw havg hall kb kw kall active total
|
|
328
|
+
local sdelta sann cann hann kann know_week
|
|
329
|
+
separator="${SEPARATOR:- ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄}"
|
|
330
|
+
line_width="${LINE_WIDTH:-67}"
|
|
331
|
+
|
|
332
|
+
sb=$(_metrics_read '(.sessions.buckets // [0,0,0,0,0]) | .[0:5] | map(. // 0) | join(" ")' "0 0 0 0 0")
|
|
333
|
+
sw=$(_num "$(_metrics_read '.sessions.week // 0' "0")")
|
|
334
|
+
sp=$(_num "$(_metrics_read '.sessions.prev // 0' "0")")
|
|
335
|
+
sall=$(_num "$(_metrics_read '.sessions.all // 0' "0")")
|
|
336
|
+
cb=$(_metrics_read '(.commits.buckets // [0,0,0,0,0]) | .[0:5] | map(. // 0) | join(" ")' "0 0 0 0 0")
|
|
337
|
+
cw=$(_num "$(_metrics_read '.commits.week // 0' "0")")
|
|
338
|
+
ca=$(_num "$(_metrics_read '.commits.authors // 0' "0")")
|
|
339
|
+
call=$(_num "$(_metrics_read '.commits.all // 0' "0")")
|
|
340
|
+
hb=$(_metrics_read '(.handoffs.buckets // [0,0,0,0,0]) | .[0:5] | map(. // 0) | join(" ")' "0 0 0 0 0")
|
|
341
|
+
hw=$(_num "$(_metrics_read '.handoffs.week // 0' "0")")
|
|
342
|
+
havg=$(_metrics_read '.handoffs.avg_resolution_days // empty' "")
|
|
343
|
+
hall=$(_num "$(_metrics_read '.handoffs.all // 0' "0")")
|
|
344
|
+
kb=$(_metrics_read '(.knowledge.buckets // [0,0,0,0,0]) | .[0:5] | map(. // 0) | join(" ")' "0 0 0 0 0")
|
|
345
|
+
kw=$(_num "$(_metrics_read '.knowledge.week // 0' "0")")
|
|
346
|
+
kall=$(_num "$(_metrics_read '.knowledge.all // 0' "0")")
|
|
347
|
+
active=$(_num "$(_metrics_read '.members.active // 0' "0")")
|
|
348
|
+
total=$(_num "$(_metrics_read '.members.total // 0' "0")")
|
|
349
|
+
|
|
350
|
+
header_left=" ◦ momentum · this week"
|
|
351
|
+
header_right="${active} of ${total} active"
|
|
352
|
+
pad=$((line_width - ${#header_left} - ${#header_right}))
|
|
353
|
+
[ "$pad" -lt 1 ] && pad=1
|
|
354
|
+
printf "%s%*s%s\n" "$header_left" "$pad" "" "$header_right"
|
|
355
|
+
|
|
356
|
+
sdelta=$(_pct_delta "$sw" "$sp")
|
|
357
|
+
sann=""
|
|
358
|
+
[ -n "$sdelta" ] && sann="${sdelta} vs last week"
|
|
359
|
+
cann=""
|
|
360
|
+
if [ "$ca" -gt 0 ] 2>/dev/null; then
|
|
361
|
+
if [ "$ca" -eq 1 ] 2>/dev/null; then cann="1 author"; else cann="${ca} authors"; fi
|
|
362
|
+
fi
|
|
363
|
+
hann=""
|
|
364
|
+
if [ -n "$havg" ]; then hann="$(_num_float "$havg")d avg resolution"; fi
|
|
365
|
+
kann="$(_commafy "$kall") artifacts total"
|
|
366
|
+
know_week="+${kw}"
|
|
367
|
+
|
|
368
|
+
printf " %-11s%5s 5-week %s %s\n\n" "sessions" "$sw" "$(_spark "$sb")" "$sann"
|
|
369
|
+
printf " %-11s%5s 5-week %s %s\n\n" "commits" "$cw" "$(_spark "$cb")" "$cann"
|
|
370
|
+
printf " %-11s%5s 5-week %s %s\n\n" "handoffs" "$hw" "$(_spark "$hb")" "$hann"
|
|
371
|
+
printf " %-11s%5s 5-week %s %s\n" "knowledge" "$know_week" "$(_spark "$kb")" "$kann"
|
|
372
|
+
echo "$separator"
|
|
373
|
+
printf " %s sessions · %s commits · %s handoffs all-time\n" "$(_commafy "$sall")" "$(_commafy "$call")" "$(_commafy "$hall")"
|
|
374
|
+
}
|
|
@@ -33,6 +33,7 @@ DESCRIPTION=""
|
|
|
33
33
|
ARTIFACT_ID=""
|
|
34
34
|
RAW_HTML=0
|
|
35
35
|
SKIP_REFERENCES=0
|
|
36
|
+
PAIR=""
|
|
36
37
|
|
|
37
38
|
while [[ $# -gt 0 ]]; do
|
|
38
39
|
case "$1" in
|
|
@@ -40,6 +41,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
40
41
|
--author) AUTHOR="$2"; shift 2 ;;
|
|
41
42
|
--description) DESCRIPTION="$2"; shift 2 ;;
|
|
42
43
|
--id) ARTIFACT_ID="$2"; shift 2 ;;
|
|
44
|
+
--pair) PAIR="$2"; shift 2 ;;
|
|
43
45
|
--raw-html) RAW_HTML=1; shift ;;
|
|
44
46
|
--no-references) SKIP_REFERENCES=1; shift ;;
|
|
45
47
|
*)
|
|
@@ -72,6 +74,7 @@ fi
|
|
|
72
74
|
if [ -f "$SCRIPT_DIR/.env" ]; then
|
|
73
75
|
EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
|
|
74
76
|
EGREGORE_API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
|
|
77
|
+
EGREGORE_USE_PUBLISHED="${EGREGORE_USE_PUBLISHED:-$(grep '^EGREGORE_USE_PUBLISHED=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
|
|
75
78
|
fi
|
|
76
79
|
|
|
77
80
|
API_URL="${EGREGORE_API_URL:-$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)}"
|
|
@@ -79,9 +82,33 @@ API_KEY="${EGREGORE_API_KEY:-}"
|
|
|
79
82
|
ORG_SLUG="$(jq -r '.slug // empty' "$CONFIG" 2>/dev/null)"
|
|
80
83
|
VIEW_BASE="https://egregore.xyz/view"
|
|
81
84
|
|
|
85
|
+
# Resolve "use published renderer" from env first, then egregore.json. The
|
|
86
|
+
# env var lets individuals override per-shell; egregore.json lets an
|
|
87
|
+
# instance (e.g. the upstream dev repo) opt in for every teammate.
|
|
88
|
+
if [ -z "${EGREGORE_USE_PUBLISHED:-}" ]; then
|
|
89
|
+
CONFIG_USE_PUBLISHED="$(jq -r '.prefer_published_artifacts // empty' "$CONFIG" 2>/dev/null)"
|
|
90
|
+
if [ "$CONFIG_USE_PUBLISHED" = "true" ]; then
|
|
91
|
+
EGREGORE_USE_PUBLISHED=1
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
82
95
|
# Public relay for OSS share endpoint
|
|
83
96
|
RELAY_URL="https://egregore-production-55f2.up.railway.app"
|
|
84
97
|
|
|
98
|
+
# --- Artifact hosting off-switch (compliance / privacy) ---
|
|
99
|
+
# An instance can disable ALL egregore.xyz publishing via `bin/settings.sh hosting off`
|
|
100
|
+
# (sets features.publishing=false). Absent/true means ON, so existing instances are
|
|
101
|
+
# unaffected. We bail BEFORE any render or upload so "off" truly does nothing and costs
|
|
102
|
+
# nothing. Exit 3 is distinct from usage errors; fire-and-forget callers ignore it.
|
|
103
|
+
# NOTE: test `!= false`, not jq's `// "true"` — `//` treats an explicit `false` as empty
|
|
104
|
+
# and would return the default, silently defeating the off-switch.
|
|
105
|
+
PUBLISHING_ENABLED="$(jq -r 'if .features.publishing == false then "false" else "true" end' "$CONFIG" 2>/dev/null || echo "true")"
|
|
106
|
+
if [ "$PUBLISHING_ENABLED" = "false" ]; then
|
|
107
|
+
echo "Artifact hosting is off for this egregore (features.publishing=false); nothing uploaded." >&2
|
|
108
|
+
echo "Turn it on with: bin/settings.sh hosting on (or: egregore settings → Hosting)." >&2
|
|
109
|
+
exit 3
|
|
110
|
+
fi
|
|
111
|
+
|
|
85
112
|
# --- Prepare HTML ---
|
|
86
113
|
TMP_HTML="/tmp/egregore-artifacts/publish-$$.html"
|
|
87
114
|
mkdir -p /tmp/egregore-artifacts
|
|
@@ -98,13 +125,21 @@ else
|
|
|
98
125
|
if [ -n "$API_KEY" ] && [ -n "$ORG_SLUG" ]; then
|
|
99
126
|
RENDER_ARGS+=(--org-slug "$ORG_SLUG" --view-base "$VIEW_BASE")
|
|
100
127
|
fi
|
|
128
|
+
# Palette family (meridian default | agronomic | sovereign). Role-token driven,
|
|
129
|
+
# so it themes any composed artifact with no extra CSS.
|
|
130
|
+
if [ -n "$PAIR" ]; then
|
|
131
|
+
RENDER_ARGS+=(--pair "$PAIR")
|
|
132
|
+
fi
|
|
101
133
|
|
|
102
134
|
# Prefer the in-repo package copy when it's present AND its dependencies
|
|
103
135
|
# have been installed — that way local edits to packages/egregore-artifacts
|
|
104
136
|
# are exercised without waiting for an npm release. Fall back to the
|
|
105
137
|
# published `npx egregore-artifacts` otherwise.
|
|
138
|
+
# Set EGREGORE_USE_PUBLISHED=1 to force the npm-published renderer even
|
|
139
|
+
# when a local install is present — useful in the upstream dev repo to
|
|
140
|
+
# dogfood what teammates and OSS users actually run.
|
|
106
141
|
LOCAL_CLI="$SCRIPT_DIR/packages/egregore-artifacts/bin/cli.js"
|
|
107
|
-
if [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
|
|
142
|
+
if [ "${EGREGORE_USE_PUBLISHED:-0}" != "1" ] && [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
|
|
108
143
|
if ! node "$LOCAL_CLI" "${RENDER_ARGS[@]}" >/dev/null 2>&1; then
|
|
109
144
|
exit 0
|
|
110
145
|
fi
|
|
@@ -158,6 +193,13 @@ if [ -n "$RESPONSE" ]; then
|
|
|
158
193
|
URL=$(echo "$RESPONSE" | jq -r '.url // empty' 2>/dev/null)
|
|
159
194
|
if [ -n "$URL" ]; then
|
|
160
195
|
echo "$URL"
|
|
196
|
+
# Register in the local artifact registry (memory/artifacts/) so this hosted
|
|
197
|
+
# artifact is findable by CONTENT, not just name — grep/ls (Claude Code /
|
|
198
|
+
# Codex, OSS), and search + graph (paid). Never fatal to the publish.
|
|
199
|
+
bash "$SCRIPT_DIR/bin/artifact-register.sh" \
|
|
200
|
+
--id "$ARTIFACT_ID" --url "$URL" --type "$TYPE" --title "$TITLE" \
|
|
201
|
+
--author "$AUTHOR" --source "$FILE" --description "$DESCRIPTION" \
|
|
202
|
+
>/dev/null 2>&1 || true
|
|
161
203
|
fi
|
|
162
204
|
fi
|
|
163
205
|
|