create-egregore 0.19.3 → 0.19.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/assets/egregore-launcher.js +3 -1
  2. package/lib/local.js +63 -6
  3. package/package.json +2 -2
  4. package/runtime/codex/.codex/hooks/search-hint.js +65 -0
  5. package/runtime/codex/.codex/hooks.json +13 -0
  6. package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +14 -10
  7. package/runtime/codex/.codex/skills/minion/SKILL.md +25 -0
  8. package/runtime/codex/.codex/skills/scroll/SKILL.md +168 -0
  9. package/runtime/codex/.codex/skills/scroll/agents/openai.yaml +4 -0
  10. package/runtime/codex/.codex/skills/scroll/assets/shell.html +542 -0
  11. package/runtime/codex/.codex/skills/search/SKILL.md +56 -0
  12. package/runtime/codex/.codex/skills/session-view/SKILL.md +25 -0
  13. package/runtime/codex/.codex/skills/thread/SKILL.md +25 -0
  14. package/runtime/codex/.codex/skills/view/SKILL.md +147 -32
  15. package/runtime/codex/.codex/skills/view/agents/openai.yaml +4 -0
  16. package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +221 -0
  17. package/runtime/codex/.codex/spec-manifest.json +3 -3
  18. package/runtime/codex/AGENTS.md +24 -3
  19. package/runtime/codex/bin/activity-data.sh +46 -4
  20. package/runtime/codex/bin/agent.sh +10 -2
  21. package/runtime/codex/bin/codex-install-skills.sh +1 -1
  22. package/runtime/codex/bin/codex-render-spec.mjs +18 -1
  23. package/runtime/codex/bin/codex-session-start.sh +1 -1
  24. package/runtime/codex/bin/codex-skill-render.mjs +13 -7
  25. package/runtime/codex/bin/codex-sync-skills.sh +4 -0
  26. package/runtime/codex/bin/graph-op.sh +56 -5
  27. package/runtime/codex/bin/graph.sh +36 -0
  28. package/runtime/codex/bin/handoff-run.sh +157 -7
  29. package/runtime/codex/bin/handoff-save-egregore.sh +6 -1
  30. package/runtime/codex/bin/index-handoff.sh +9 -3
  31. package/runtime/codex/bin/lib/context.sh +89 -17
  32. package/runtime/codex/bin/lib/dashboard-artifact.sh +1 -1
  33. package/runtime/codex/bin/lib/git-sync.sh +35 -9
  34. package/runtime/codex/bin/lib/greeting.sh +25 -3
  35. package/runtime/codex/bin/publish-artifact.sh +29 -1
  36. package/runtime/codex/manifest.json +16 -1
@@ -23,6 +23,8 @@
23
23
 
24
24
  CTX_DIR=$(mktemp -d)
25
25
 
26
+ source "$SCRIPT_DIR/bin/lib/handoff-meta.sh" >/dev/null 2>/dev/null || true
27
+
26
28
  # Time of day
27
29
  HOUR=$(date +%H)
28
30
  if [ "$HOUR" -lt 12 ]; then TIME_OF_DAY="morning"
@@ -177,6 +179,31 @@ fi
177
179
  )
178
180
  fi
179
181
 
182
+ # --- "Working on": latest session/handoff/wrap topic per person (file-based) ---
183
+ # Gives every team surface (greeting "around", dashboard) something legible in
184
+ # local mode, where git branches are usually empty for teammates.
185
+ _WM_TAB=$(printf '\t')
186
+ WORK_MAP=$(
187
+ {
188
+ for DIR in "$SCRIPT_DIR/memory/sessions" "$SCRIPT_DIR/memory/handoffs" "$SCRIPT_DIR/memory/wraps"; do
189
+ [ -d "$DIR" ] || continue
190
+ find -L "$DIR" -name '*.md' -not -name 'index*' -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -30 | while read -r WFILE; do
191
+ [ -z "$WFILE" ] && continue
192
+ W_AUTH=$(grep -m1 '^\*\*Author\*\*:' "$WFILE" 2>/dev/null | sed 's/^\*\*Author\*\*:[[:space:]]*//')
193
+ W_DATE=$(grep -m1 '^\*\*Date\*\*:' "$WFILE" 2>/dev/null | sed 's/^\*\*Date\*\*:[[:space:]]*//')
194
+ W_TOPIC=$(grep -m1 '^# ' "$WFILE" 2>/dev/null | sed 's/^#[[:space:]]*//; s/^Session:[[:space:]]*//; s/^Handoff:[[:space:]]*//; s/^Wrap:[[:space:]]*//')
195
+ [ -z "$W_AUTH" ] && continue
196
+ [ -z "$W_TOPIC" ] && continue
197
+ printf '%s%s%s%s%s\n' "$W_AUTH" "$_WM_TAB" "$W_DATE" "$_WM_TAB" "$W_TOPIC"
198
+ done
199
+ done
200
+ } | sort -t"$_WM_TAB" -k1,1 -k2,2r | sort -t"$_WM_TAB" -k1,1 -u | while IFS="$_WM_TAB" read -r WM_NAME WM_DATE WM_TOPIC; do
201
+ [ -z "$WM_NAME" ] && continue
202
+ WM_LC=$(echo "$WM_NAME" | tr '[:upper:]' '[:lower:]')
203
+ printf '%s%s%s\n' "$WM_LC" "$_WM_TAB" "$WM_TOPIC"
204
+ done | jq -Rn --arg tab "$_WM_TAB" '[inputs | split($tab) | select(length>=2) | {(.[0]): (.[1] // "")}] | add // {}' 2>/dev/null || echo "{}"
205
+ )
206
+
180
207
  # --- Relative time + epoch helpers (cross-platform) ---
181
208
  NOW_EPOCH=$(date +%s)
182
209
 
@@ -270,8 +297,9 @@ fi
270
297
  BRANCHES_JSON=$(echo "$BRANCHES_JSON" | jq --arg e "+${EXTRA} more" '[.[0:2][], $e]' 2>/dev/null || echo "$BRANCHES_JSON")
271
298
  fi
272
299
 
273
- ENTRY=$(jq -n --arg name "$PNAME" --arg seen "$LAST_SEEN_REL" --argjson sort "$LAST_SEEN_EPOCH" --argjson branches "$BRANCHES_JSON" \
274
- '{name: $name, last_seen: $seen, last_seen_sort: $sort, branches: $branches}')
300
+ WORK=$(echo "$WORK_MAP" | jq -r --arg n "$PNAME" '.[$n] // ""' 2>/dev/null)
301
+ ENTRY=$(jq -n --arg name "$PNAME" --arg seen "$LAST_SEEN_REL" --argjson sort "$LAST_SEEN_EPOCH" --argjson branches "$BRANCHES_JSON" --arg work "$WORK" \
302
+ '{name: $name, last_seen: $seen, last_seen_sort: $sort, branches: $branches, working_on: $work}')
275
303
  $FIRST || PRESENCE="$PRESENCE,"
276
304
  PRESENCE="$PRESENCE$ENTRY"
277
305
  FIRST=false
@@ -320,18 +348,9 @@ fi
320
348
  for AF in $ADDRESSED; do
321
349
  [ -z "$AF" ] && continue
322
350
  AF_NAME=$(basename "$AF" .md)
323
- AF_AUTHOR=$(sed -n 's/^\*\*Author\*\*: *//p' "$AF" 2>/dev/null | head -1)
324
- if [ -z "$AF_AUTHOR" ]; then
325
- AF_AUTHOR=$(sed -n 's/^From: *//p' "$AF" 2>/dev/null | head -1)
326
- fi
327
- AF_TOPIC=$(sed -n 's/^# Handoff: *//p' "$AF" 2>/dev/null | head -1)
328
- if [ -z "$AF_TOPIC" ]; then
329
- AF_TOPIC=$(sed -n 's/^# *//p' "$AF" 2>/dev/null | head -1)
330
- fi
331
- AF_DATE=$(sed -n 's/^\*\*Date\*\*: *//p' "$AF" 2>/dev/null | head -1)
332
- if [ -z "$AF_DATE" ]; then
333
- AF_DATE=$(sed -n 's/^Date: *//p' "$AF" 2>/dev/null | head -1)
334
- fi
351
+ AF_AUTHOR=$(eg_handoff_author "$AF")
352
+ AF_TOPIC=$(eg_handoff_topic "$AF")
353
+ AF_DATE=$(eg_handoff_date "$AF")
335
354
  # Extract repo state table if present
336
355
  AF_REPO_STATE="[]"
337
356
  AF_REPO_TABLE=$(awk '/^## Repo State/{found=1; next} found && /^#/{exit} found && /^\|[^-]/ && !/^\| Repo/{print}' "$AF" 2>/dev/null || true)
@@ -352,9 +371,14 @@ fi
352
371
  $FIRST || JSON="$JSON,"
353
372
  $FIRST || RICH="$RICH,"
354
373
  JSON="$JSON\"$AF_NAME\""
355
- AF_TOPIC_ESC=$(echo "$AF_TOPIC" | sed 's/"/\\"/g')
356
- AF_AUTHOR_ESC=$(echo "$AF_AUTHOR" | sed 's/"/\\"/g')
357
- RICH="$RICH{\"name\":\"$AF_NAME\",\"author\":\"$AF_AUTHOR_ESC\",\"topic\":\"$AF_TOPIC_ESC\",\"date\":\"$AF_DATE\",\"repoState\":$AF_REPO_STATE}"
374
+ AF_ENTRY=$(jq -cn \
375
+ --arg name "$AF_NAME" \
376
+ --arg author "$AF_AUTHOR" \
377
+ --arg topic "$AF_TOPIC" \
378
+ --arg date "$AF_DATE" \
379
+ --argjson repoState "$AF_REPO_STATE" \
380
+ '{name:$name, author:$author, topic:$topic, date:$date, repoState:$repoState}' 2>/dev/null || echo "{}")
381
+ RICH="$RICH$AF_ENTRY"
358
382
  FIRST=false
359
383
  done
360
384
  JSON="$JSON]"
@@ -364,6 +388,54 @@ fi
364
388
  echo "$RICH" > "$CTX_DIR/addressed_rich"
365
389
  ) &
366
390
 
391
+ # 6.5. Pending questions addressed to user (background)
392
+ (
393
+ PENDING_JSON="[]"
394
+ QDIR="$SCRIPT_DIR/memory/knowledge/questions"
395
+ if [ -d "$QDIR" ]; then
396
+ # Match against the same identity variants used for handoffs (display name,
397
+ # github first-name, people-file name) so "to: oz" matches author "oguzhan".
398
+ _DISPLAY_Q=$(jq -r '.display_name // empty' "$STATE_FILE" 2>/dev/null)
399
+ _GH_NAME_Q=$(jq -r '.github_name // empty' "$STATE_FILE" 2>/dev/null)
400
+ _FIRST_NAME_Q=$(echo "$_GH_NAME_Q" | awk '{print tolower($1)}')
401
+ _PEOPLE_FILE_Q="$SCRIPT_DIR/memory/people/$(echo "$AUTHOR" | tr '[:upper:]' '[:lower:]').md"
402
+ _PEOPLE_NAME_Q=""
403
+ [ -f "$_PEOPLE_FILE_Q" ] && _PEOPLE_NAME_Q=$(sed -n 's/^# *//p' "$_PEOPLE_FILE_Q" 2>/dev/null | head -1 | awk '{print tolower($1)}')
404
+
405
+ LINES=""
406
+ for QF in "$QDIR"/*.md; do
407
+ [ -f "$QF" ] || continue
408
+ Q_TO=$(sed -n 's/^to:[[:space:]]*//p' "$QF" 2>/dev/null | head -1 | tr -d '"' | tr '[:upper:]' '[:lower:]' | awk '{print $1}')
409
+ [ -z "$Q_TO" ] && continue
410
+ _MATCH="false"
411
+ for _V in "$AUTHOR" "$_DISPLAY_Q" "$_FIRST_NAME_Q" "$_PEOPLE_NAME_Q"; do
412
+ [ -z "$_V" ] && continue
413
+ _V_LC=$(echo "$_V" | tr '[:upper:]' '[:lower:]')
414
+ [ "$Q_TO" = "$_V_LC" ] && _MATCH="true" && break
415
+ done
416
+ [ "$_MATCH" = "true" ] || continue
417
+ Q_STATUS=$(sed -n 's/^status:[[:space:]]*//p' "$QF" 2>/dev/null | head -1 | tr -d '"')
418
+ [ "$Q_STATUS" = "pending" ] || continue
419
+ Q_FROM=$(sed -n 's/^from:[[:space:]]*//p' "$QF" 2>/dev/null | head -1 | tr -d '"')
420
+ Q_TOPIC=$(sed -n 's/^topic:[[:space:]]*//p' "$QF" 2>/dev/null | head -1 | tr -d '"')
421
+ Q_HID=$(sed -n 's/^harvest_id:[[:space:]]*//p' "$QF" 2>/dev/null | head -1 | tr -d '"')
422
+ Q_REL="${QF#$SCRIPT_DIR/}"
423
+ LINE=$(jq -nc \
424
+ --arg from "$Q_FROM" \
425
+ --arg topic "$Q_TOPIC" \
426
+ --arg hid "$Q_HID" \
427
+ --arg file "$Q_REL" \
428
+ '{from:$from, topic:$topic, harvest_id:$hid, file:$file}' 2>/dev/null)
429
+ [ -n "$LINE" ] && LINES="$LINES$LINE
430
+ "
431
+ done
432
+ if [ -n "$LINES" ]; then
433
+ PENDING_JSON=$(echo "$LINES" | jq -sc '.' 2>/dev/null || echo "[]")
434
+ fi
435
+ fi
436
+ echo "$PENDING_JSON" > "$CTX_DIR/pending_questions"
437
+ ) &
438
+
367
439
  # 7. Graph health (background — zero added latency, runs in parallel)
368
440
  (
369
441
  if [ "$LOCAL_MODE" = "true" ]; then
@@ -90,7 +90,7 @@ mkdir -p /tmp
90
90
  printf '## Team Activity\n\n'
91
91
  printf '| Name | Last Seen | Working On |\n'
92
92
  printf '|------|-----------|------------|\n'
93
- echo "$_DB_TEAM_FILTERED" | jq -r '.[] | "| \(.name) | \(.last_seen) | \(.branches | join(", ")) |"' 2>/dev/null || true
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
94
  printf '\n'
95
95
  fi
96
96
  fi
@@ -26,7 +26,20 @@ git config pull.rebase true 2>/dev/null || true
26
26
  export GIT_HTTP_LOW_SPEED_LIMIT=1000 # abort if <1KB/s
27
27
  export GIT_HTTP_LOW_SPEED_TIME=10 # for 10 seconds
28
28
 
29
- git fetch origin --quiet 2>/dev/null &
29
+ # Attendant fast path: the ambient daemon (bin/attendant.sh) fetches origin,
30
+ # memory, and managed repos every few minutes. If its warm marker is fresh,
31
+ # refs are already up to date — skip the network fetches and launch on local
32
+ # ops only. Upstream fetch (framework update check) is not covered by the
33
+ # attendant and stays unconditional below.
34
+ _REFS_FRESH="false"
35
+ _ATT_SLUG=$(jq -r '.slug // "egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "egregore")
36
+ _ATT_MARKER="$HOME/.egregore/attendant/${_ATT_SLUG}-$(echo -n "$SCRIPT_DIR" | cksum | cut -d' ' -f1).warm-ts"
37
+ if [ -f "$_ATT_MARKER" ]; then
38
+ _ATT_AGE=$(( $(date +%s) - $(cat "$_ATT_MARKER" 2>/dev/null || echo 0) ))
39
+ [ "$_ATT_AGE" -lt 360 ] && _REFS_FRESH="true"
40
+ fi
41
+
42
+ [ "$_REFS_FRESH" != "true" ] && git fetch origin --quiet 2>/dev/null &
30
43
 
31
44
  # Fetch upstream framework (for update check — non-blocking)
32
45
  # Default: official egregore-core repo. Set upstream_url in egregore.json to override,
@@ -40,17 +53,19 @@ fi
40
53
 
41
54
  # Sync memory in parallel (symlink or direct directory — both valid)
42
55
  MEMORY_SYNCED="false"
43
- if [ -d "$SCRIPT_DIR/memory/.git" ]; then
56
+ if [ -d "$SCRIPT_DIR/memory/.git" ] && [ "$_REFS_FRESH" != "true" ]; then
44
57
  git -C "$SCRIPT_DIR/memory" fetch origin --quiet 2>/dev/null &
45
58
  fi
46
59
 
47
60
  # Fetch managed repos in parallel
48
61
  MANAGED_REPOS=$(jq -r '(.repos[]? // empty) | if type == "object" then .name else . end' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
49
- for REPO in $MANAGED_REPOS; do
50
- if [ -d "$SCRIPT_DIR/../$REPO/.git" ]; then
51
- git -C "$SCRIPT_DIR/../$REPO" fetch origin --quiet 2>/dev/null &
52
- fi
53
- done
62
+ if [ "$_REFS_FRESH" != "true" ]; then
63
+ for REPO in $MANAGED_REPOS; do
64
+ if [ -d "$SCRIPT_DIR/../$REPO/.git" ]; then
65
+ git -C "$SCRIPT_DIR/../$REPO" fetch origin --quiet 2>/dev/null &
66
+ fi
67
+ done
68
+ fi
54
69
 
55
70
  # Wait for all fetches
56
71
  wait 2>/dev/null || true
@@ -93,6 +108,16 @@ else
93
108
  HEALTH_GIT="fail"
94
109
  fi
95
110
 
111
+ # --- Guarded staging -------------------------------------------------------
112
+ # git_add_guarded() lives in the shared lib so the /handoff auto-save uses the
113
+ # exact same logic. Fallback to plain `git add -A` if the lib can't be sourced,
114
+ # so an unattended auto-save never silently no-ops.
115
+ # shellcheck source=bin/lib/git-safe.sh
116
+ . "$SCRIPT_DIR/bin/lib/git-safe.sh" 2>/dev/null || true
117
+ if ! type git_add_guarded >/dev/null 2>&1; then
118
+ git_add_guarded() { git add -A 2>/dev/null || true; }
119
+ fi
120
+
96
121
  # --- Setup develop (wrapped — failures set HEALTH_GIT but don't crash) ---
97
122
  setup_develop() {
98
123
  # Ensure develop branch exists locally
@@ -143,8 +168,9 @@ setup_develop() {
143
168
  if [[ "$CURRENT_BRANCH" != "develop" ]]; then
144
169
  # Check for uncommitted work (staged + unstaged + untracked in tracked dirs)
145
170
  if [ -n "$(git status --porcelain 2>/dev/null | head -1)" ]; then
146
- # Save uncommitted work so nothing is lost
147
- git add -A 2>/dev/null
171
+ # Save uncommitted work so nothing is lost (guarded: never auto-commit
172
+ # stray submodule pointers from sibling repos in the checkout)
173
+ git_add_guarded
148
174
  git commit -m "Auto-save: uncommitted work from $CURRENT_BRANCH" --quiet 2>/dev/null || true
149
175
  SAVED_BRANCH="$CURRENT_BRANCH"
150
176
  fi
@@ -112,8 +112,26 @@ if [ "$ADDRESSED_COUNT" -gt 0 ] 2>/dev/null && [ "$ADDRESSED_COUNT" != "0" ]; th
112
112
  done
113
113
  fi
114
114
 
115
- # Fallback: last activity if no handoffs
116
- if [ "$ADDRESSED_COUNT" = "0" ] || [ -z "$ADDRESSED_COUNT" ]; then
115
+ # Pending questions addressed to you (one summary line — /answer to engage)
116
+ PENDING_Q=$(cat "$CTX_DIR/pending_questions" 2>/dev/null || echo "[]")
117
+ PENDING_Q_COUNT=$(echo "$PENDING_Q" | jq 'length' 2>/dev/null || echo "0")
118
+ if [ "$PENDING_Q_COUNT" -gt 0 ] 2>/dev/null && [ "$PENDING_Q_COUNT" != "0" ]; then
119
+ PQ_SENDERS=$(echo "$PENDING_Q" | jq -r '[.[].from] | unique | join(", ")' 2>/dev/null)
120
+ if [ "$PENDING_Q_COUNT" = "1" ]; then
121
+ PQ_NOUN="question"
122
+ else
123
+ PQ_NOUN="questions"
124
+ fi
125
+ if [ -n "$PQ_SENDERS" ]; then
126
+ printf " ◐ %s pending %s from %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN" "$PQ_SENDERS"
127
+ else
128
+ printf " ◐ %s pending %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN"
129
+ fi
130
+ fi
131
+
132
+ # Fallback: last activity if no handoffs and no pending questions
133
+ if { [ "$ADDRESSED_COUNT" = "0" ] || [ -z "$ADDRESSED_COUNT" ]; } \
134
+ && { [ "$PENDING_Q_COUNT" = "0" ] || [ -z "$PENDING_Q_COUNT" ]; }; then
117
135
  LAST_ACTIVITY=$(cat "$CTX_DIR/activity" 2>/dev/null || echo "")
118
136
  if [ -n "$LAST_ACTIVITY" ]; then
119
137
  LA_TIME=$(echo "$LAST_ACTIVITY" | cut -d'|' -f1)
@@ -131,7 +149,7 @@ if [ "$TEAM_DATA_COUNT" -gt 0 ] 2>/dev/null && [ "$TEAM_DATA_COUNT" != "0" ]; th
131
149
  echo " ◦ around"
132
150
  # Presence roster with online/offline dots (hide inactive >3 days)
133
151
  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
152
+ echo "$TEAM_DATA" | jq -r '.[] | ((.working_on // "")) as $w | (.branches // []) as $b | "\(.name)\t\(.last_seen_sort)\t\(.last_seen)\t\(if $w != "" then $w else ($b | join(", ")) end)"' 2>/dev/null | while IFS=$'\t' read -r P_NAME P_EPOCH P_SEEN P_BRANCHES; do
135
153
  [ -z "$P_NAME" ] && continue
136
154
  # Skip if no recent activity (within recency window)
137
155
  if [ "$P_EPOCH" -le 0 ] 2>/dev/null; then
@@ -256,6 +274,10 @@ if [ -n "${BOARD_URL:-}" ]; then
256
274
  printf " ◆ %s (board)\n" "$BOARD_URL"
257
275
  fi
258
276
 
277
+ if [ -n "${LOOM_DOCTOR_BRIEF:-}" ]; then
278
+ printf " %s\n" "$LOOM_DOCTOR_BRIEF"
279
+ fi
280
+
259
281
  # Framework updates come through PRs to develop — no separate auto-update channel.
260
282
  # The develop sync above already keeps framework files current.
261
283
  # Use /update for manual upstream pulls when needed.
@@ -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,6 +82,16 @@ 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,13 +111,21 @@ else
98
111
  if [ -n "$API_KEY" ] && [ -n "$ORG_SLUG" ]; then
99
112
  RENDER_ARGS+=(--org-slug "$ORG_SLUG" --view-base "$VIEW_BASE")
100
113
  fi
114
+ # Palette family (meridian default | agronomic | sovereign). Role-token driven,
115
+ # so it themes any composed artifact with no extra CSS.
116
+ if [ -n "$PAIR" ]; then
117
+ RENDER_ARGS+=(--pair "$PAIR")
118
+ fi
101
119
 
102
120
  # Prefer the in-repo package copy when it's present AND its dependencies
103
121
  # have been installed — that way local edits to packages/egregore-artifacts
104
122
  # are exercised without waiting for an npm release. Fall back to the
105
123
  # published `npx egregore-artifacts` otherwise.
124
+ # Set EGREGORE_USE_PUBLISHED=1 to force the npm-published renderer even
125
+ # when a local install is present — useful in the upstream dev repo to
126
+ # dogfood what teammates and OSS users actually run.
106
127
  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
128
+ if [ "${EGREGORE_USE_PUBLISHED:-0}" != "1" ] && [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
108
129
  if ! node "$LOCAL_CLI" "${RENDER_ARGS[@]}" >/dev/null 2>&1; then
109
130
  exit 0
110
131
  fi
@@ -158,6 +179,13 @@ if [ -n "$RESPONSE" ]; then
158
179
  URL=$(echo "$RESPONSE" | jq -r '.url // empty' 2>/dev/null)
159
180
  if [ -n "$URL" ]; then
160
181
  echo "$URL"
182
+ # Register in the local artifact registry (memory/artifacts/) so this hosted
183
+ # artifact is findable by CONTENT, not just name — grep/ls (Claude Code /
184
+ # Codex, OSS), and search + graph (paid). Never fatal to the publish.
185
+ bash "$SCRIPT_DIR/bin/artifact-register.sh" \
186
+ --id "$ARTIFACT_ID" --url "$URL" --type "$TYPE" --title "$TITLE" \
187
+ --author "$AUTHOR" --source "$FILE" --description "$DESCRIPTION" \
188
+ >/dev/null 2>&1 || true
161
189
  fi
162
190
  fi
163
191
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "source": "egregore-runtime",
3
3
  "policy": "public-safe subset derived from .syncignore; built by scripts/build-runtime-bundle.mjs",
4
- "skillCount": 51,
4
+ "skillCount": 56,
5
5
  "skills": [
6
6
  "activity",
7
7
  "add",
@@ -29,6 +29,7 @@
29
29
  "issue",
30
30
  "me",
31
31
  "meeting",
32
+ "minion",
32
33
  "note",
33
34
  "onboarding",
34
35
  "pr",
@@ -40,6 +41,9 @@
40
41
  "reflect",
41
42
  "review-pr",
42
43
  "save",
44
+ "scroll",
45
+ "search",
46
+ "session-view",
43
47
  "setup",
44
48
  "summon",
45
49
  "sync-repos",
@@ -47,6 +51,7 @@
47
51
  "telemetry",
48
52
  "test",
49
53
  "the-spiral",
54
+ "thread",
50
55
  "todo",
51
56
  "tui-design",
52
57
  "tutorial",
@@ -60,6 +65,7 @@
60
65
  ".codex/config.toml",
61
66
  ".codex/hooks.json",
62
67
  ".codex/hooks/branch-guard.js",
68
+ ".codex/hooks/search-hint.js",
63
69
  ".codex/skills/activity/SKILL.md",
64
70
  ".codex/skills/add/SKILL.md",
65
71
  ".codex/skills/announce/SKILL.md",
@@ -86,6 +92,7 @@
86
92
  ".codex/skills/issue/SKILL.md",
87
93
  ".codex/skills/me/SKILL.md",
88
94
  ".codex/skills/meeting/SKILL.md",
95
+ ".codex/skills/minion/SKILL.md",
89
96
  ".codex/skills/note/SKILL.md",
90
97
  ".codex/skills/onboarding/SKILL.md",
91
98
  ".codex/skills/pr/SKILL.md",
@@ -97,6 +104,11 @@
97
104
  ".codex/skills/reflect/SKILL.md",
98
105
  ".codex/skills/review-pr/SKILL.md",
99
106
  ".codex/skills/save/SKILL.md",
107
+ ".codex/skills/scroll/SKILL.md",
108
+ ".codex/skills/scroll/agents/openai.yaml",
109
+ ".codex/skills/scroll/assets/shell.html",
110
+ ".codex/skills/search/SKILL.md",
111
+ ".codex/skills/session-view/SKILL.md",
100
112
  ".codex/skills/setup/SKILL.md",
101
113
  ".codex/skills/summon/SKILL.md",
102
114
  ".codex/skills/sync-repos/SKILL.md",
@@ -104,11 +116,14 @@
104
116
  ".codex/skills/telemetry/SKILL.md",
105
117
  ".codex/skills/test/SKILL.md",
106
118
  ".codex/skills/the-spiral/SKILL.md",
119
+ ".codex/skills/thread/SKILL.md",
107
120
  ".codex/skills/todo/SKILL.md",
108
121
  ".codex/skills/tui-design/SKILL.md",
109
122
  ".codex/skills/tutorial/SKILL.md",
110
123
  ".codex/skills/update/SKILL.md",
111
124
  ".codex/skills/view/SKILL.md",
125
+ ".codex/skills/view/agents/openai.yaml",
126
+ ".codex/skills/view/assets/compose-scaffold.html",
112
127
  ".codex/skills/visual-explain/SKILL.md",
113
128
  ".codex/skills/wrap/SKILL.md",
114
129
  ".codex/spec-manifest.json",