create-egregore 0.19.33 → 0.20.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.
- package/assets/egregore-launcher.js +141 -14
- package/bin/cli.js +19 -3
- package/lib/connect-runtime.js +4 -2
- package/lib/local.js +15 -1
- package/lib/prime-runtime.js +208 -0
- package/lib/setup.js +66 -5
- package/package.json +4 -3
- package/runtime/codex/.codex/config.toml +3 -0
- package/runtime/codex/.codex/skills/archive/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/branch/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/checkup/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/commit/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/contribute/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/delete-user/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/ingest/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/ingest-corpus/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/issue/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/me/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/meeting/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/note/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/onboarding/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/pr/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/pull/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/push/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/reflect/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/review-pr/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/save/SKILL.md +3 -1
- package/runtime/codex/.codex/skills/slack-connect/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/summon/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/sync-repos/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/telegram-connect/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/telemetry/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/test/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/tutorial/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/update/SKILL.md +1 -1
- package/runtime/codex/.codex/spec-manifest.json +5 -5
- package/runtime/codex/AGENTS.md +41 -35
- package/runtime/codex/bin/activity-data.sh +4 -8
- package/runtime/codex/bin/agent.sh +17 -5
- package/runtime/codex/bin/attendant.sh +13 -0
- package/runtime/codex/bin/autosave.sh +27 -1
- package/runtime/codex/bin/codex-render-spec.mjs +33 -32
- package/runtime/codex/bin/codex-session-start.sh +3 -1
- package/runtime/codex/bin/codex-sync-skills.sh +6 -1
- package/runtime/codex/bin/graph-batch.sh +25 -6
- package/runtime/codex/bin/graph-op.sh +5 -4
- package/runtime/codex/bin/graph.sh +31 -5
- package/runtime/codex/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/codex/bin/handoff-run.sh +8 -3
- package/runtime/codex/bin/handoff-save-egregore.sh +19 -7
- package/runtime/codex/bin/ingest.py +341 -10
- package/runtime/codex/bin/lib/context.sh +26 -1
- package/runtime/codex/bin/lib/git-message.sh +37 -0
- package/runtime/codex/bin/lib/git-sync.sh +10 -2
- package/runtime/codex/bin/lib/greeting.sh +4 -1
- package/runtime/codex/bin/lib/worktree-links.sh +25 -0
- package/runtime/codex/bin/session-autosave.sh +7 -1
- package/runtime/codex/bin/settings.sh +1 -1
- package/runtime/codex/manifest.json +10 -1
- package/runtime/pi/.codex/config.toml +3 -0
- package/runtime/pi/.codex/skills/archive/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/branch/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/checkup/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/commit/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/contribute/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/delete-user/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/ingest/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/ingest-corpus/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/issue/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/me/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/meeting/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/note/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/onboarding/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/pr/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/pull/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/push/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/reflect/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/review-pr/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/save/SKILL.md +3 -1
- package/runtime/pi/.codex/skills/slack-connect/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/summon/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/sync-repos/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/telemetry/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/test/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/tutorial/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/update/SKILL.md +1 -1
- package/runtime/pi/.codex/spec-manifest.json +5 -5
- package/runtime/pi/.pi/APPEND_SYSTEM.md +57 -33
- package/runtime/pi/.pi/extensions/egregore.ts +17 -6
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +41 -35
- package/runtime/pi/bin/activity-data.sh +4 -8
- package/runtime/pi/bin/agent.sh +17 -5
- package/runtime/pi/bin/attendant.sh +13 -0
- package/runtime/pi/bin/autosave.sh +27 -1
- package/runtime/pi/bin/codex-render-spec.mjs +33 -32
- package/runtime/pi/bin/codex-session-start.sh +3 -1
- package/runtime/pi/bin/codex-sync-skills.sh +6 -1
- package/runtime/pi/bin/graph-batch.sh +25 -6
- package/runtime/pi/bin/graph-op.sh +5 -4
- package/runtime/pi/bin/graph.sh +31 -5
- package/runtime/pi/bin/handoff-pr-backfill.sh +1 -1
- package/runtime/pi/bin/handoff-run.sh +8 -3
- package/runtime/pi/bin/handoff-save-egregore.sh +19 -7
- package/runtime/pi/bin/ingest.py +341 -10
- package/runtime/pi/bin/lib/context.sh +26 -1
- package/runtime/pi/bin/lib/git-message.sh +37 -0
- package/runtime/pi/bin/lib/git-sync.sh +10 -2
- 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/bin/pi-render-spec.mjs +52 -26
- package/runtime/pi/bin/session-autosave.sh +7 -1
- package/runtime/pi/bin/settings.sh +1 -1
- package/runtime/pi/manifest.json +10 -1
- package/runtime/prime/.claude/context/notification-consent.md +66 -0
- package/runtime/prime/.codex/config.toml +20 -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-corpus/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 +127 -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 +416 -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 +488 -0
- package/runtime/prime/bin/activity-data.sh +238 -0
- package/runtime/prime/bin/agent.sh +787 -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 +435 -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 +237 -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 +676 -0
- package/runtime/prime/bin/handoff-save-egregore.sh +224 -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 +1011 -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-message.sh +37 -0
- package/runtime/prime/bin/lib/git-sync.sh +414 -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 +147 -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 +215 -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 +181 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# greeting.sh — Greeting output renderer for session-start.sh
|
|
3
|
+
#
|
|
4
|
+
# Renders the full session greeting:
|
|
5
|
+
# - ASCII art banner
|
|
6
|
+
# - Identity line (org/repo + user + branch)
|
|
7
|
+
# - Momentum board (sessions, commits, handoffs, knowledge)
|
|
8
|
+
# - Pending questions signal
|
|
9
|
+
# - Health footer
|
|
10
|
+
# - Alias migration
|
|
11
|
+
# - Session context JSON (hidden, for Claude)
|
|
12
|
+
# - Soul file inclusion
|
|
13
|
+
# - Telemetry emit
|
|
14
|
+
# - First session welcome
|
|
15
|
+
#
|
|
16
|
+
# Inputs: SCRIPT_DIR, STATE_FILE, CONFIG, CTX_DIR, BRANCH, COMMITS_AHEAD,
|
|
17
|
+
# AUTHOR, LOCAL_MODE, MEMORY_SYNCED, SAVED_BRANCH,
|
|
18
|
+
# HEALTH_*, FRAMEWORK_VERSION, TIME_OF_DAY, EGREGORE_SESSION_ID,
|
|
19
|
+
# FIRST_SESSION, DISPLAY_NAME_STATE, DASHBOARD_URL
|
|
20
|
+
|
|
21
|
+
# --- Output greeting for Claude to display ---
|
|
22
|
+
cat << 'GREETING'
|
|
23
|
+
|
|
24
|
+
███████╗ ██████╗ ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
25
|
+
██╔════╝██╔════╝ ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
|
|
26
|
+
█████╗ ██║ ███╗██████╔╝█████╗ ██║ ███╗██║ ██║██████╔╝█████╗
|
|
27
|
+
██╔══╝ ██║ ██║██╔══██╗██╔══╝ ██║ ██║██║ ██║██╔══██╗██╔══╝
|
|
28
|
+
███████╗╚██████╔╝██║ ██║███████╗╚██████╔╝╚██████╔╝██║ ██║███████╗
|
|
29
|
+
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
|
30
|
+
|
|
31
|
+
GREETING
|
|
32
|
+
|
|
33
|
+
# --- Ornamented status ---
|
|
34
|
+
REPO_NAME=$(jq -r '.repo_name // "egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
35
|
+
GITHUB_ORG_DISPLAY=$(jq -r '.github_org // ""' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
36
|
+
ORG_NAME=$(jq -r '.org_name // ""' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
|
|
37
|
+
|
|
38
|
+
DISPLAY_NAME=""
|
|
39
|
+
if [ -f "$STATE_FILE" ]; then
|
|
40
|
+
DISPLAY_NAME=$(jq -r '.display_name // .name // empty' "$STATE_FILE" 2>/dev/null)
|
|
41
|
+
fi
|
|
42
|
+
GREETING_NAME="${DISPLAY_NAME:-$AUTHOR}"
|
|
43
|
+
|
|
44
|
+
# --- Line 1: Org/Repo + User + Branch (primary info) ---
|
|
45
|
+
SEPARATOR=" ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄"
|
|
46
|
+
|
|
47
|
+
# Build identity line: Org/repo on left, user + branch on right
|
|
48
|
+
if [ "$LOCAL_MODE" = "true" ]; then
|
|
49
|
+
IDENTITY_LEFT=" Egregore"
|
|
50
|
+
else
|
|
51
|
+
IDENTITY_LEFT=" ${GITHUB_ORG_DISPLAY}/${REPO_NAME}"
|
|
52
|
+
fi
|
|
53
|
+
BRANCH_COMPACT="$BRANCH"
|
|
54
|
+
if [ "$COMMITS_AHEAD" -gt 0 ] 2>/dev/null; then
|
|
55
|
+
BRANCH_COMPACT="${BRANCH} · ${COMMITS_AHEAD}↑"
|
|
56
|
+
fi
|
|
57
|
+
IDENTITY_RIGHT="${GREETING_NAME} · ${BRANCH_COMPACT}"
|
|
58
|
+
LINE_WIDTH=67
|
|
59
|
+
ID_LEFT_LEN=${#IDENTITY_LEFT}
|
|
60
|
+
ID_RIGHT_LEN=${#IDENTITY_RIGHT}
|
|
61
|
+
ID_PADDING=$((LINE_WIDTH - ID_LEFT_LEN - ID_RIGHT_LEN))
|
|
62
|
+
if [ "$ID_PADDING" -lt 1 ]; then ID_PADDING=1; fi
|
|
63
|
+
printf "\n%s%*s%s\n" "$IDENTITY_LEFT" "$ID_PADDING" "" "$IDENTITY_RIGHT"
|
|
64
|
+
echo "$SEPARATOR"
|
|
65
|
+
|
|
66
|
+
# --- Momentum board ---
|
|
67
|
+
source "$SCRIPT_DIR/bin/lib/metrics.sh"
|
|
68
|
+
_render_momentum_board
|
|
69
|
+
|
|
70
|
+
# Pending questions and handoffs addressed to you. These are lightweight
|
|
71
|
+
# discovery beats; management stays in /answer and /activity.
|
|
72
|
+
PENDING_Q=$(cat "$CTX_DIR/pending_questions" 2>/dev/null || echo "[]")
|
|
73
|
+
PENDING_Q_COUNT=$(echo "$PENDING_Q" | jq 'length' 2>/dev/null || echo "0")
|
|
74
|
+
if [ "$PENDING_Q_COUNT" -gt 0 ] 2>/dev/null && [ "$PENDING_Q_COUNT" != "0" ]; then
|
|
75
|
+
PQ_SENDERS=$(echo "$PENDING_Q" | jq -r '[.[].from] | unique | join(", ")' 2>/dev/null)
|
|
76
|
+
if [ "$PENDING_Q_COUNT" = "1" ]; then
|
|
77
|
+
PQ_NOUN="question"
|
|
78
|
+
else
|
|
79
|
+
PQ_NOUN="questions"
|
|
80
|
+
fi
|
|
81
|
+
if [ -n "$PQ_SENDERS" ]; then
|
|
82
|
+
printf " ◐ %s pending %s from %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN" "$PQ_SENDERS"
|
|
83
|
+
else
|
|
84
|
+
printf " ◐ %s pending %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN"
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
ADDRESSED_RICH=$(cat "$CTX_DIR/addressed_rich" 2>/dev/null || echo "[]")
|
|
88
|
+
ADDRESSED_COUNT=$(echo "$ADDRESSED_RICH" | jq 'length' 2>/dev/null || echo "0")
|
|
89
|
+
if [ "$ADDRESSED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
90
|
+
printf " ◇ %s handoffs for you — say \"show my handoffs\" to review or close\n" "$ADDRESSED_COUNT"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Show auto-save notice if work was committed from a previous branch
|
|
94
|
+
if [ -n "$SAVED_BRANCH" ]; then
|
|
95
|
+
echo " ✓ Auto-saved uncommitted work on $SAVED_BRANCH"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# --- Footer: health + repos + memory (tertiary) ---
|
|
99
|
+
echo "$SEPARATOR"
|
|
100
|
+
|
|
101
|
+
# Build compact footer line
|
|
102
|
+
if [ "$LOCAL_MODE" = "true" ]; then
|
|
103
|
+
# Local mode: only check github + git, skip api-key/graph/telegram
|
|
104
|
+
HAS_FAILURE="false"
|
|
105
|
+
FAILED_SERVICES=""
|
|
106
|
+
for pair in "github:$HEALTH_GITHUB" "git:$HEALTH_GIT"; do
|
|
107
|
+
svc="${pair%%:*}"
|
|
108
|
+
svc_status="${pair#*:}"
|
|
109
|
+
if [ "$svc_status" = "fail" ]; then
|
|
110
|
+
HAS_FAILURE="true"
|
|
111
|
+
FAILED_SERVICES="${FAILED_SERVICES} ${svc} ✗"
|
|
112
|
+
fi
|
|
113
|
+
done
|
|
114
|
+
|
|
115
|
+
if [ "$HAS_FAILURE" = "true" ]; then
|
|
116
|
+
echo " ⚠${FAILED_SERVICES} — run /checkup"
|
|
117
|
+
else
|
|
118
|
+
if [ "${FRAMEWORK_UPDATED:-false}" = "true" ]; then
|
|
119
|
+
printf " ◆ updated\n"
|
|
120
|
+
else
|
|
121
|
+
printf " ✓ ready\n"
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
else
|
|
125
|
+
# Connected mode: check all services
|
|
126
|
+
HAS_FAILURE="false"
|
|
127
|
+
FAILED_SERVICES=""
|
|
128
|
+
for pair in "github:$HEALTH_GITHUB" "git:$HEALTH_GIT" "api-key:$HEALTH_APIKEY" "graph:$HEALTH_GRAPH" "telegram:$HEALTH_TELEGRAM"; do
|
|
129
|
+
svc="${pair%%:*}"
|
|
130
|
+
svc_status="${pair#*:}"
|
|
131
|
+
if [ "$svc_status" = "fail" ]; then
|
|
132
|
+
HAS_FAILURE="true"
|
|
133
|
+
FAILED_SERVICES="${FAILED_SERVICES} ${svc} ✗"
|
|
134
|
+
fi
|
|
135
|
+
done
|
|
136
|
+
|
|
137
|
+
if [ "$HAS_FAILURE" = "true" ]; then
|
|
138
|
+
echo " ⚠${FAILED_SERVICES} — run /checkup"
|
|
139
|
+
else
|
|
140
|
+
# Compact footer: ready + memory on one line, repos on next if present
|
|
141
|
+
FOOTER_LEFT=" ✓ ready"
|
|
142
|
+
FOOTER_RIGHT=""
|
|
143
|
+
if [ "$MEMORY_SYNCED" = "true" ]; then
|
|
144
|
+
FOOTER_RIGHT="◆ memory synced"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
FL_LEN=${#FOOTER_LEFT}
|
|
148
|
+
FR_LEN=${#FOOTER_RIGHT}
|
|
149
|
+
F_PAD=$((LINE_WIDTH - FL_LEN - FR_LEN))
|
|
150
|
+
if [ "$F_PAD" -lt 1 ]; then F_PAD=1; fi
|
|
151
|
+
printf "%s%*s%s\n" "$FOOTER_LEFT" "$F_PAD" "" "$FOOTER_RIGHT"
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Framework update trail — an auto-update overwrites every framework path from
|
|
156
|
+
# upstream, local edits included. It used to surface as the footer word
|
|
157
|
+
# "updated" in local mode and as nothing at all in connected mode, which is not
|
|
158
|
+
# enough notice for files being replaced under you. Name the count, name the
|
|
159
|
+
# first few, and point at the commit that did it.
|
|
160
|
+
if [ "${FRAMEWORK_UPDATED:-false}" = "true" ] && [ "${FRAMEWORK_UPDATED_COUNT:-0}" -gt 0 ]; then
|
|
161
|
+
FU_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "")
|
|
162
|
+
printf " ◆ framework updated from upstream — %s file(s) replaced: %s\n" \
|
|
163
|
+
"$FRAMEWORK_UPDATED_COUNT" "${FRAMEWORK_UPDATED_FILES% }"
|
|
164
|
+
if [ -n "$FU_SHA" ]; then
|
|
165
|
+
printf " local edits to framework paths are replaced by design — git show %s\n" "$FU_SHA"
|
|
166
|
+
fi
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
# Autosave trail — background saves (Stop-hook, sweep, SessionEnd) since the
|
|
170
|
+
# last greeting. The ledger is machine-scoped; this is where sweep rescues of
|
|
171
|
+
# abandoned sessions become visible to the user.
|
|
172
|
+
AUTOSAVE_LOG="${EGREGORE_AUTOSAVE_LOG:-$HOME/.egregore/autosave.log}"
|
|
173
|
+
AUTOSAVE_SEEN="${AUTOSAVE_LOG}.seen"
|
|
174
|
+
if [ -f "$AUTOSAVE_LOG" ]; then
|
|
175
|
+
TOTAL_AS=$(grep -c '|autosave|' "$AUTOSAVE_LOG" 2>/dev/null || echo 0)
|
|
176
|
+
SEEN_AS=$(cat "$AUTOSAVE_SEEN" 2>/dev/null || echo 0)
|
|
177
|
+
case "$SEEN_AS" in ''|*[!0-9]*) SEEN_AS=0 ;; esac
|
|
178
|
+
if [ "$TOTAL_AS" -gt "$SEEN_AS" ]; then
|
|
179
|
+
NEW_AS=$((TOTAL_AS - SEEN_AS))
|
|
180
|
+
MERGED_AS=$(grep '|autosave|' "$AUTOSAVE_LOG" 2>/dev/null | tail -n "$NEW_AS" | grep -c '|merged|' || echo 0)
|
|
181
|
+
if [ "$MERGED_AS" -gt 0 ]; then
|
|
182
|
+
printf " ⟲ auto-saved %s non-coding save(s) → develop while you were away\n" "$MERGED_AS"
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
printf '%s' "$TOTAL_AS" > "$AUTOSAVE_SEEN" 2>/dev/null || true
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
# Staged auto-saves awaiting the user's merge (the /autosave consent gate).
|
|
189
|
+
# Live gh query so the line persists until the PRs actually merge — the
|
|
190
|
+
# ledger cursor above only reports once. Fail-soft when gh/network is out.
|
|
191
|
+
# Shown only while the autosave experiment is enabled: stale PRs from a
|
|
192
|
+
# disabled experiment should not nag every greeting.
|
|
193
|
+
AUTOSAVE_ON=$(jq -r '.autosave_enabled // false' "$STATE_FILE" 2>/dev/null)
|
|
194
|
+
if [ "$AUTOSAVE_ON" = "true" ] && command -v gh >/dev/null 2>&1; then
|
|
195
|
+
GH_SELF=$(jq -r '.github_username // empty' "$STATE_FILE" 2>/dev/null)
|
|
196
|
+
if [ -n "$GH_SELF" ]; then
|
|
197
|
+
WAITING_AS=$(gh pr list --state open --author "$GH_SELF" --limit 20 \
|
|
198
|
+
--json number,title --jq '[.[] | select(.title | startswith("Auto-save:")) | .number] | join(", #")' 2>/dev/null || true)
|
|
199
|
+
if [ -n "$WAITING_AS" ]; then
|
|
200
|
+
printf " ⟲ auto-saves awaiting your merge: PR #%s — say \"merge my auto-saves\"\n" "$WAITING_AS"
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# Greeting links. Org config `pinned_links` in egregore.json replaces the
|
|
206
|
+
# default dashboard + board links. Entries are strings or {url, label}.
|
|
207
|
+
# (OSC 8 hyperlink — clickable text in supported terminals)
|
|
208
|
+
PINNED_LINKS=$(jq -c '.pinned_links // []' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "[]")
|
|
209
|
+
if [ "$(printf '%s' "$PINNED_LINKS" | jq 'length' 2>/dev/null || echo 0)" -gt 0 ]; then
|
|
210
|
+
printf '%s' "$PINNED_LINKS" | jq -r '.[] |
|
|
211
|
+
if type == "string" then " ◆ \(.)"
|
|
212
|
+
elif (.label // "") != "" then " ◆ \(.label): \(.url)"
|
|
213
|
+
else " ◆ \(.url)" end' 2>/dev/null
|
|
214
|
+
else
|
|
215
|
+
if [ -n "${DASHBOARD_URL:-}" ]; then
|
|
216
|
+
printf " ◆ %s\n" "$DASHBOARD_URL"
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
if [ -n "${BOARD_URL:-}" ]; then
|
|
220
|
+
printf " ◆ %s (board)\n" "$BOARD_URL"
|
|
221
|
+
fi
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
if [ -n "${LOOM_DOCTOR_BRIEF:-}" ]; then
|
|
225
|
+
# Indent every line — printf ' %s' indents only the first line of a
|
|
226
|
+
# multiline brief, which misaligns the card and hides follow-up warnings
|
|
227
|
+
# from the fast-path signal-line scraper (it keys on "^ ").
|
|
228
|
+
printf '%s\n' "$LOOM_DOCTOR_BRIEF" | sed 's/^/ /'
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# --- Creator review gate: pending turns on owned scrolls/surfaces ---
|
|
232
|
+
# This is deliberately filesystem-only and fail-soft. The two environment seams
|
|
233
|
+
# make the scan safe to exercise without touching the instance memory repo.
|
|
234
|
+
_print_pending_scroll_turns() {
|
|
235
|
+
local memory_root="${EGREGORE_MEMORY_ROOT:-$SCRIPT_DIR/memory}"
|
|
236
|
+
local person="${EGREGORE_PERSON:-${AUTHOR:-}}"
|
|
237
|
+
local rows="" file slug owner count surface_file
|
|
238
|
+
|
|
239
|
+
if [ -z "$person" ] && [ -f "${STATE_FILE:-}" ]; then
|
|
240
|
+
person=$(jq -r '.github_username // .display_name // .name // empty' "$STATE_FILE" 2>/dev/null || true)
|
|
241
|
+
fi
|
|
242
|
+
[ -n "$person" ] || return 0
|
|
243
|
+
[ -d "$memory_root" ] || return 0
|
|
244
|
+
|
|
245
|
+
for file in "$memory_root"/scrolls/.events/*.jsonl; do
|
|
246
|
+
[ -f "$file" ] || continue
|
|
247
|
+
slug=$(basename "$file" .jsonl)
|
|
248
|
+
[[ "$slug" =~ ^[A-Za-z0-9._-]+$ ]] || continue
|
|
249
|
+
safe_slug=$(printf '%s' "$slug" | tr -d '\000-\037\177')
|
|
250
|
+
[ "$safe_slug" = "$slug" ] || continue
|
|
251
|
+
owner=$(sed -nE 's/^[[:space:]-]*(\*\*)?creator(\*\*)?[[:space:]]*:[[:space:]]*//p' "$memory_root/scrolls/$slug.md" 2>/dev/null | head -1 | sed 's/[[:space:]]*$//')
|
|
252
|
+
[ "$owner" = "$person" ] || continue
|
|
253
|
+
count=$(jq -s -r '
|
|
254
|
+
def event_id:
|
|
255
|
+
if (.turn | type) == "object" then .turn.id
|
|
256
|
+
elif (.turn | type) == "string" then .turn
|
|
257
|
+
else .id end;
|
|
258
|
+
def received($events):
|
|
259
|
+
[$events[] | select(.type == "turn-received")
|
|
260
|
+
| {id: event_id, answers: (.turn.answers // .answers // [])}
|
|
261
|
+
| select(.id != null)] | unique_by(.id);
|
|
262
|
+
def review_id: event_id;
|
|
263
|
+
def is_absorbed($events; $id):
|
|
264
|
+
any($events[]; .type == "version-published" and ((.absorbs // .version.absorbs // .record.absorbs // []) | index($id) != null));
|
|
265
|
+
def is_applied($events; $id):
|
|
266
|
+
any($events[]; .type == "turn-applied" and (event_id == $id));
|
|
267
|
+
def is_declined($events; $received; $id):
|
|
268
|
+
([$received[] | select(.id == $id)] | .[0]) as $turn |
|
|
269
|
+
([$events[] | select(.type == "turn-reviewed" and review_id == $id)] | .[0]) as $review |
|
|
270
|
+
if $review == null then false
|
|
271
|
+
else if (($turn.answers // []) | length) == 0 then $review.disposition == "declined"
|
|
272
|
+
else (($turn.answers // [])
|
|
273
|
+
| map(($review.answers // {})[.fork] // $review.disposition)
|
|
274
|
+
| map(select(. == "accepted")) | length) == 0
|
|
275
|
+
end
|
|
276
|
+
end;
|
|
277
|
+
. as $events
|
|
278
|
+
| ($events | received($events)) as $received
|
|
279
|
+
| [$received[] as $turn
|
|
280
|
+
| select((is_absorbed($events; $turn.id) | not))
|
|
281
|
+
| select((is_declined($events; $received; $turn.id) | not))
|
|
282
|
+
| select(if $mode == "scroll" then true else (is_applied($events; $turn.id) | not) end)]
|
|
283
|
+
| length
|
|
284
|
+
' --arg mode scroll "$file" 2>/dev/null) || continue
|
|
285
|
+
[[ "$count" =~ ^[0-9]+$ ]] || return 0
|
|
286
|
+
[ "$count" -gt 0 ] && rows+="${safe_slug}"$'\t'"${count}"$'\n'
|
|
287
|
+
done
|
|
288
|
+
|
|
289
|
+
for file in "$memory_root"/harvests/.events/*.jsonl; do
|
|
290
|
+
[ -f "$file" ] || continue
|
|
291
|
+
slug=$(basename "$file" .jsonl)
|
|
292
|
+
[[ "$slug" =~ ^[A-Za-z0-9._-]+$ ]] || continue
|
|
293
|
+
safe_slug=$(printf '%s' "$slug" | tr -d '\000-\037\177')
|
|
294
|
+
[ "$safe_slug" = "$slug" ] || continue
|
|
295
|
+
surface_file="$memory_root/harvests/$slug.json"
|
|
296
|
+
[ -f "$surface_file" ] || continue
|
|
297
|
+
owner=$(jq -r '.author // empty' "$surface_file" 2>/dev/null) || continue
|
|
298
|
+
[ "$owner" = "$person" ] || continue
|
|
299
|
+
count=$(jq -s -r '
|
|
300
|
+
def event_id:
|
|
301
|
+
if (.turn | type) == "object" then .turn.id
|
|
302
|
+
elif (.turn | type) == "string" then .turn
|
|
303
|
+
else .id end;
|
|
304
|
+
def received($events):
|
|
305
|
+
[$events[] | select(.type == "turn-received")
|
|
306
|
+
| {id: event_id, answers: (.turn.answers // .answers // [])}
|
|
307
|
+
| select(.id != null)] | unique_by(.id);
|
|
308
|
+
def review_id: event_id;
|
|
309
|
+
def is_absorbed($events; $id): false;
|
|
310
|
+
def is_applied($events; $id):
|
|
311
|
+
any($events[]; .type == "turn-applied" and (event_id == $id));
|
|
312
|
+
def is_declined($events; $received; $id):
|
|
313
|
+
([$received[] | select(.id == $id)] | .[0]) as $turn |
|
|
314
|
+
([$events[] | select(.type == "turn-reviewed" and review_id == $id)] | .[0]) as $review |
|
|
315
|
+
if $review == null then false
|
|
316
|
+
else if (($turn.answers // []) | length) == 0 then $review.disposition == "declined"
|
|
317
|
+
else (($turn.answers // [])
|
|
318
|
+
| map(($review.answers // {})[.fork] // $review.disposition)
|
|
319
|
+
| map(select(. == "accepted")) | length) == 0
|
|
320
|
+
end
|
|
321
|
+
end;
|
|
322
|
+
. as $events
|
|
323
|
+
| ($events | received($events)) as $received
|
|
324
|
+
| [$received[] as $turn
|
|
325
|
+
| select((is_applied($events; $turn.id) | not))
|
|
326
|
+
| select((is_declined($events; $received; $turn.id) | not))]
|
|
327
|
+
| length
|
|
328
|
+
' --arg mode harvest "$file" 2>/dev/null) || continue
|
|
329
|
+
[[ "$count" =~ ^[0-9]+$ ]] || return 0
|
|
330
|
+
[ "$count" -gt 0 ] && rows+="${safe_slug}"$'\t'"${count}"$'\n'
|
|
331
|
+
done
|
|
332
|
+
|
|
333
|
+
[ -n "$rows" ] || return 0
|
|
334
|
+
local summary total details
|
|
335
|
+
summary=$(printf '%s' "$rows" | awk -F '\t' 'NF == 2 { totals[$1] += $2 } END { for (slug in totals) print slug "\t" totals[slug] }' | sort -t $'\t' -k1,1) || return 0
|
|
336
|
+
[ -n "$summary" ] || return 0
|
|
337
|
+
total=$(printf '%s\n' "$summary" | awk -F '\t' '{ total += $2 } END { print total + 0 }') || return 0
|
|
338
|
+
details=$(printf '%s\n' "$summary" | awk -F '\t' '{printf "%s%s (%s)", (NR == 1 ? "" : ", "), $1, $2}') || return 0
|
|
339
|
+
[ -n "$details" ] || return 0
|
|
340
|
+
printf " ⧖ %s pending turn(s) on your scrolls: %s\n" "$total" "$details"
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
_print_pending_scroll_turns
|
|
344
|
+
|
|
345
|
+
# Framework updates come through PRs to develop — no separate auto-update channel.
|
|
346
|
+
# The develop sync above already keeps framework files current.
|
|
347
|
+
# Use /update for manual upstream pulls when needed.
|
|
348
|
+
|
|
349
|
+
# --- One-time migration: fix aliases to use 'claude "start"' ---
|
|
350
|
+
# v1: 'claude start' → 'claude' (cross-instance bug)
|
|
351
|
+
# v2: 'claude' → 'claude "start"' (blank prompt — auto-sends first message)
|
|
352
|
+
ALIAS_VERSION=$(jq -r '.alias_version // 0' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
353
|
+
if [ "$ALIAS_VERSION" -lt 2 ] 2>/dev/null; then
|
|
354
|
+
for profile in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile"; do
|
|
355
|
+
if [ -f "$profile" ] && grep -q "$SCRIPT_DIR" "$profile" 2>/dev/null; then
|
|
356
|
+
# Replace any egregore alias pointing to this directory with the correct command
|
|
357
|
+
# Handles: && claude start, && claude, && claude "start" (idempotent)
|
|
358
|
+
sed -i.bak "s|&& claude start|\\&\\& claude \"start\"|g; s|&& claude'|\\&\\& claude \"start\"'|g" "$profile" 2>/dev/null && rm -f "${profile}.bak" || true
|
|
359
|
+
fi
|
|
360
|
+
done
|
|
361
|
+
if [ -f "$STATE_FILE" ] && jq . "$STATE_FILE" >/dev/null 2>&1; then
|
|
362
|
+
jq '. + {"alias_fixed": true, "alias_version": 2}' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
363
|
+
fi
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
echo ""
|
|
367
|
+
|
|
368
|
+
# --- Session context (hidden, for Claude) ---
|
|
369
|
+
CONTEXT_HANDOFFS=$(cat "$CTX_DIR/handoffs" 2>/dev/null || echo "[]")
|
|
370
|
+
CONTEXT_HANDOFFS=$(printf '%s' "$CONTEXT_HANDOFFS" | jq -c 'map(if .preview then .preview |= .[0:80] else . end)' 2>/dev/null || printf '%s' "$CONTEXT_HANDOFFS")
|
|
371
|
+
CONTEXT_ADDRESSED=$(cat "$CTX_DIR/addressed" 2>/dev/null || echo "[]")
|
|
372
|
+
CONTEXT_QUESTS=$(cat "$CTX_DIR/quests" 2>/dev/null || echo "[]")
|
|
373
|
+
CONTEXT_QUESTS=$(printf '%s' "$CONTEXT_QUESTS" | jq -c 'if length > 20 then .[0:20] + ["+\(length - 20) more"] else . end' 2>/dev/null || printf '%s' "$CONTEXT_QUESTS")
|
|
374
|
+
CONTEXT_ACTIVITY=$(cat "$CTX_DIR/activity" 2>/dev/null || echo "")
|
|
375
|
+
CONTEXT_TEAM=$(cat "$CTX_DIR/team" 2>/dev/null || echo "[]")
|
|
376
|
+
# Trim the team blob for greeting injection: 8 most-recent people, drop sort
|
|
377
|
+
# keys, one branch each. This trimmed view is all the session ever sees —
|
|
378
|
+
# CTX_DIR is deleted at the end of this script — a deliberate cap to keep
|
|
379
|
+
# hook stdout inline-sized. Untrimmed this is the single largest field in
|
|
380
|
+
# session-context.
|
|
381
|
+
CONTEXT_TEAM=$(printf '%s' "$CONTEXT_TEAM" | jq -c '.[0:8] | map({name, last_seen, working_on: ((.working_on // "")[0:80]), branches: ((.branches // [])[0:1])})' 2>/dev/null || printf '%s' "$CONTEXT_TEAM")
|
|
382
|
+
CONTEXT_SOUL=$(cat "$CTX_DIR/soul_summary" 2>/dev/null || echo "")
|
|
383
|
+
CONTEXT_LIFECYCLE=$(cat "$CTX_DIR/lifecycle" 2>/dev/null || echo '{"merged_prs":[],"implemented_handoffs":[]}')
|
|
384
|
+
CONTEXT_PULSE=$(cat "$CTX_DIR/pulse_brief" 2>/dev/null || echo '{}')
|
|
385
|
+
if [ -f "$CTX_DIR/metrics" ]; then
|
|
386
|
+
CONTEXT_METRICS=$(jq -c . "$CTX_DIR/metrics" 2>/dev/null || echo "{}")
|
|
387
|
+
[ -n "$CONTEXT_METRICS" ] || CONTEXT_METRICS="{}"
|
|
388
|
+
else
|
|
389
|
+
CONTEXT_METRICS="{}"
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
# --- Write compact subagent context cache (reuses already-gathered data) ---
|
|
393
|
+
SUBAGENT_CTX="/tmp/egregore-subagent-ctx-${EGREGORE_SESSION_ID}.txt"
|
|
394
|
+
(
|
|
395
|
+
SA_ORG_NAME=$(jq -r '.org_name // "Unknown"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "Unknown")
|
|
396
|
+
SA_GITHUB_ORG=$(jq -r '.github_org // "unknown"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "unknown")
|
|
397
|
+
|
|
398
|
+
# Format quests list
|
|
399
|
+
SA_QUESTS="none"
|
|
400
|
+
if [ "$CONTEXT_QUESTS" != "[]" ]; then
|
|
401
|
+
SA_QUESTS=$(echo "$CONTEXT_QUESTS" | jq -r '.[]' 2>/dev/null | paste -sd', ' - 2>/dev/null || echo "none")
|
|
402
|
+
fi
|
|
403
|
+
|
|
404
|
+
# Format recent handoffs
|
|
405
|
+
SA_HANDOFFS="none"
|
|
406
|
+
if [ "$CONTEXT_HANDOFFS" != "[]" ]; then
|
|
407
|
+
SA_HANDOFFS=$(echo "$CONTEXT_HANDOFFS" | jq -r '.[] | .name' 2>/dev/null | head -5 | paste -sd', ' - 2>/dev/null || echo "none")
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
cat > "$SUBAGENT_CTX" << SAEOF
|
|
411
|
+
<!-- egregore-context
|
|
412
|
+
Organization: $SA_ORG_NAME (github: $SA_GITHUB_ORG)
|
|
413
|
+
Session: $BRANCH — ${EGREGORE_SESSION_ID}
|
|
414
|
+
Active quests: $SA_QUESTS
|
|
415
|
+
Recent handoffs: $SA_HANDOFFS
|
|
416
|
+
Memory: memory/ is a symlink to shared knowledge base. Use bin/graph.sh for Neo4j queries.
|
|
417
|
+
-->
|
|
418
|
+
SAEOF
|
|
419
|
+
) 2>/dev/null || true
|
|
420
|
+
|
|
421
|
+
# Emit the context JSON compacted (jq -c) — nested blobs arrive pretty-printed
|
|
422
|
+
# from CTX_DIR and the whitespace alone is ~1KB of hook stdout. Fall back to
|
|
423
|
+
# the raw heredoc if jq can't parse (a malformed fragment must not eat context).
|
|
424
|
+
_CTX_JSON=$(cat << CTXEOF
|
|
425
|
+
{
|
|
426
|
+
"framework_version": "$FRAMEWORK_VERSION",
|
|
427
|
+
"time_of_day": "$TIME_OF_DAY",
|
|
428
|
+
"dashboard_url": "${DASHBOARD_URL:-}",
|
|
429
|
+
"recent_handoffs": $CONTEXT_HANDOFFS,
|
|
430
|
+
"addressed_to_user": $CONTEXT_ADDRESSED,
|
|
431
|
+
"quests": $CONTEXT_QUESTS,
|
|
432
|
+
"last_user_activity": "$CONTEXT_ACTIVITY",
|
|
433
|
+
"team_recent_memory": $CONTEXT_TEAM,
|
|
434
|
+
"soul_self_summary": "$CONTEXT_SOUL",
|
|
435
|
+
"lifecycle": $CONTEXT_LIFECYCLE,
|
|
436
|
+
"momentum": $CONTEXT_METRICS,
|
|
437
|
+
"pulse": $CONTEXT_PULSE
|
|
438
|
+
}
|
|
439
|
+
CTXEOF
|
|
440
|
+
)
|
|
441
|
+
printf '\n<!-- session-context\n%s\n-->\n' \
|
|
442
|
+
"$(printf '%s' "$_CTX_JSON" | jq -c . 2>/dev/null || printf '%s' "$_CTX_JSON")"
|
|
443
|
+
|
|
444
|
+
# Include soul file if present
|
|
445
|
+
if [ -f "$SCRIPT_DIR/egregore.md" ]; then
|
|
446
|
+
echo ""
|
|
447
|
+
echo "<!-- egregore-soul"
|
|
448
|
+
cat "$SCRIPT_DIR/egregore.md"
|
|
449
|
+
echo "-->"
|
|
450
|
+
fi
|
|
451
|
+
|
|
452
|
+
# Point at the latest soul reflection instead of inlining it. The full
|
|
453
|
+
# document is several KB; injected verbatim it pushed hook stdout past the
|
|
454
|
+
# harness inline threshold, which turns the greeting into a file the model
|
|
455
|
+
# must Read back — a whole extra API round-trip on every boot.
|
|
456
|
+
if [ -d "$SCRIPT_DIR/memory/soul" ]; then
|
|
457
|
+
LATEST_REFLECTION=$(ls -t "$SCRIPT_DIR/memory/soul/"*.md 2>/dev/null | head -1 || true)
|
|
458
|
+
if [ -n "$LATEST_REFLECTION" ]; then
|
|
459
|
+
echo "<!-- latest-reflection: memory/soul/$(basename "$LATEST_REFLECTION") — read when org identity, culture, or history context matters -->"
|
|
460
|
+
fi
|
|
461
|
+
fi
|
|
462
|
+
|
|
463
|
+
# --- Flush leftover telemetry from previous session (background) ---
|
|
464
|
+
# If the previous session exited without a clean flush (terminal closed,
|
|
465
|
+
# crash, kill -9), events are still in the local buffer. Drain them now.
|
|
466
|
+
bash "$SCRIPT_DIR/bin/telemetry.sh" flush 2>/dev/null &
|
|
467
|
+
|
|
468
|
+
# --- Emit session_start telemetry (background, non-blocking) ---
|
|
469
|
+
bash "$SCRIPT_DIR/bin/telemetry.sh" emit "session_start" \
|
|
470
|
+
"$(jq -n --arg branch "$BRANCH" '{branch: $branch}')" 2>/dev/null &
|
|
471
|
+
|
|
472
|
+
# --- Health check-in (background, non-blocking) ---
|
|
473
|
+
bash "$SCRIPT_DIR/bin/startup-check.sh" >/dev/null 2>&1 &
|
|
474
|
+
|
|
475
|
+
# --- Warm npx cache for egregore-artifacts (background, throttled) ---
|
|
476
|
+
# publish-artifact.sh spawns `npx egregore-artifacts` — first run in a
|
|
477
|
+
# fresh npx cache pays a 5-10s npm download. Warmup is throttled to
|
|
478
|
+
# once per hour via a marker file so we don't storm npm when a user
|
|
479
|
+
# opens many tabs, and don't start runaway retry loops when offline.
|
|
480
|
+
_WARM_TS_FILE="$HOME/.cache/egregore/npx-warm-ts"
|
|
481
|
+
mkdir -p "$(dirname "$_WARM_TS_FILE")" 2>/dev/null
|
|
482
|
+
_WARM_LAST=$(cat "$_WARM_TS_FILE" 2>/dev/null || echo 0)
|
|
483
|
+
_WARM_NOW=$(date +%s)
|
|
484
|
+
if [ $(( _WARM_NOW - _WARM_LAST )) -gt 3600 ]; then
|
|
485
|
+
(npx -y egregore-artifacts@latest --help >/dev/null 2>&1 \
|
|
486
|
+
&& echo "$_WARM_NOW" > "$_WARM_TS_FILE" &) >/dev/null 2>&1
|
|
487
|
+
fi
|
|
488
|
+
|
|
489
|
+
# Clean up temp files
|
|
490
|
+
rm -rf "$CTX_DIR"
|
|
491
|
+
|
|
492
|
+
# --- First session welcome ---
|
|
493
|
+
if [ -z "$FIRST_SESSION" ] && [ -f "$STATE_FILE" ]; then
|
|
494
|
+
FIRST_SESSION=$(jq -r '.first_session // false' "$STATE_FILE" 2>/dev/null)
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
if [ "$FIRST_SESSION" = "true" ]; then
|
|
498
|
+
echo ""
|
|
499
|
+
echo " Welcome! This is your first session."
|
|
500
|
+
echo ""
|
|
501
|
+
echo "IMPORTANT: Display the above greeting exactly as-is (ASCII art + ornamented status). Then ask the user if they'd like a quick onboarding tour (run /onboarding), or if they want to jump straight in."
|
|
502
|
+
# Clear the flag so it only shows once
|
|
503
|
+
jq '.first_session = false' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
504
|
+
else
|
|
505
|
+
# --- Tutorial tip (if onboarding done but tutorial not) ---
|
|
506
|
+
TUTORIAL_COMPLETE="true"
|
|
507
|
+
if [ -f "$STATE_FILE" ]; then
|
|
508
|
+
TUTORIAL_COMPLETE=$(jq -r '.tutorial_complete // false' "$STATE_FILE" 2>/dev/null || echo "true")
|
|
509
|
+
fi
|
|
510
|
+
|
|
511
|
+
if [ "$TUTORIAL_COMPLETE" != "true" ]; then
|
|
512
|
+
echo " Tip: Run /tutorial to learn the core loop."
|
|
513
|
+
fi
|
|
514
|
+
|
|
515
|
+
echo ""
|
|
516
|
+
echo "IMPORTANT: Display the above greeting to the user exactly as-is (preserve the ASCII art formatting and ornamented status) on their first message. Then ask: What are you working on?"
|
|
517
|
+
echo ""
|
|
518
|
+
echo "BRANCH RULE: When the user responds with what they're working on, your FIRST action is to create a working branch: git fetch origin develop --quiet && git checkout -b dev/{author}/{topic-slug} origin/develop. Do this BEFORE any other work. Derive the topic slug from their description. If they ask a pure question with no work intent, skip branching."
|
|
519
|
+
fi
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cross-platform hash helpers — sourced by scripts that need hashing.
|
|
3
|
+
|
|
4
|
+
# Compute MD5 hash of a string (macOS + Linux compatible)
|
|
5
|
+
_md5() {
|
|
6
|
+
local input="$1"
|
|
7
|
+
echo -n "$input" | md5 2>/dev/null || echo -n "$input" | md5sum 2>/dev/null | cut -d' ' -f1
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
# Compute project hash (used for per-instance file isolation)
|
|
11
|
+
_proj_hash() {
|
|
12
|
+
_md5 "${SCRIPT_DIR:-$PWD}"
|
|
13
|
+
}
|