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.
Files changed (154) hide show
  1. package/assets/egregore-launcher.js +410 -26
  2. package/bin/cli.js +34 -20
  3. package/lib/local.js +84 -11
  4. package/lib/pi-runtime.js +186 -0
  5. package/lib/setup.js +56 -11
  6. package/lib/ui.js +1 -1
  7. package/package.json +8 -6
  8. package/runtime/codex/.codex/hooks/search-hint.js +65 -0
  9. package/runtime/codex/.codex/hooks.json +13 -0
  10. package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +14 -10
  11. package/runtime/codex/.codex/skills/minion/SKILL.md +25 -0
  12. package/runtime/codex/.codex/skills/scroll/SKILL.md +168 -0
  13. package/runtime/codex/.codex/skills/scroll/agents/openai.yaml +4 -0
  14. package/runtime/codex/.codex/skills/scroll/assets/shell.html +542 -0
  15. package/runtime/codex/.codex/skills/search/SKILL.md +56 -0
  16. package/runtime/codex/.codex/skills/session-view/SKILL.md +25 -0
  17. package/runtime/codex/.codex/skills/thread/SKILL.md +25 -0
  18. package/runtime/codex/.codex/skills/view/SKILL.md +147 -32
  19. package/runtime/codex/.codex/skills/view/agents/openai.yaml +4 -0
  20. package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +221 -0
  21. package/runtime/codex/.codex/spec-manifest.json +4 -4
  22. package/runtime/codex/AGENTS.md +31 -5
  23. package/runtime/codex/bin/activity-data.sh +46 -4
  24. package/runtime/codex/bin/agent.sh +10 -2
  25. package/runtime/codex/bin/codex-install-skills.sh +1 -1
  26. package/runtime/codex/bin/codex-render-spec.mjs +24 -2
  27. package/runtime/codex/bin/codex-session-start.sh +6 -60
  28. package/runtime/codex/bin/codex-skill-render.mjs +20 -12
  29. package/runtime/codex/bin/codex-sync-skills.sh +4 -0
  30. package/runtime/codex/bin/graph-op.sh +56 -5
  31. package/runtime/codex/bin/graph.sh +36 -0
  32. package/runtime/codex/bin/handoff-run.sh +157 -7
  33. package/runtime/codex/bin/handoff-save-egregore.sh +6 -1
  34. package/runtime/codex/bin/index-handoff.sh +9 -3
  35. package/runtime/codex/bin/lib/context.sh +97 -18
  36. package/runtime/codex/bin/lib/dashboard-artifact.sh +1 -1
  37. package/runtime/codex/bin/lib/git-sync.sh +35 -9
  38. package/runtime/codex/bin/lib/greeting.sh +30 -104
  39. package/runtime/codex/bin/lib/metrics.sh +374 -0
  40. package/runtime/codex/bin/publish-artifact.sh +43 -1
  41. package/runtime/codex/bin/settings.sh +274 -0
  42. package/runtime/codex/manifest.json +18 -1
  43. package/runtime/pi/.codex/config.toml +15 -0
  44. package/runtime/pi/.codex/hooks/branch-guard.js +242 -0
  45. package/runtime/pi/.codex/hooks/search-hint.js +65 -0
  46. package/runtime/pi/.codex/hooks.json +30 -0
  47. package/runtime/pi/.codex/skills/activity/SKILL.md +70 -0
  48. package/runtime/pi/.codex/skills/add/SKILL.md +25 -0
  49. package/runtime/pi/.codex/skills/announce/SKILL.md +54 -0
  50. package/runtime/pi/.codex/skills/answer/SKILL.md +25 -0
  51. package/runtime/pi/.codex/skills/archive/SKILL.md +41 -0
  52. package/runtime/pi/.codex/skills/ask/SKILL.md +59 -0
  53. package/runtime/pi/.codex/skills/branch/SKILL.md +25 -0
  54. package/runtime/pi/.codex/skills/checkup/SKILL.md +41 -0
  55. package/runtime/pi/.codex/skills/commit/SKILL.md +25 -0
  56. package/runtime/pi/.codex/skills/contribute/SKILL.md +25 -0
  57. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +25 -0
  58. package/runtime/pi/.codex/skills/dashboard/SKILL.md +59 -0
  59. package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +74 -0
  60. package/runtime/pi/.codex/skills/delete-user/SKILL.md +25 -0
  61. package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +25 -0
  62. package/runtime/pi/.codex/skills/emissary/SKILL.md +41 -0
  63. package/runtime/pi/.codex/skills/env/SKILL.md +25 -0
  64. package/runtime/pi/.codex/skills/handoff/SKILL.md +67 -0
  65. package/runtime/pi/.codex/skills/harvest/SKILL.md +107 -0
  66. package/runtime/pi/.codex/skills/ingest/SKILL.md +25 -0
  67. package/runtime/pi/.codex/skills/ingest-google/SKILL.md +25 -0
  68. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +41 -0
  69. package/runtime/pi/.codex/skills/invite/SKILL.md +40 -0
  70. package/runtime/pi/.codex/skills/issue/SKILL.md +41 -0
  71. package/runtime/pi/.codex/skills/me/SKILL.md +25 -0
  72. package/runtime/pi/.codex/skills/meeting/SKILL.md +41 -0
  73. package/runtime/pi/.codex/skills/minion/SKILL.md +25 -0
  74. package/runtime/pi/.codex/skills/note/SKILL.md +25 -0
  75. package/runtime/pi/.codex/skills/onboarding/SKILL.md +41 -0
  76. package/runtime/pi/.codex/skills/pr/SKILL.md +25 -0
  77. package/runtime/pi/.codex/skills/project/SKILL.md +41 -0
  78. package/runtime/pi/.codex/skills/pull/SKILL.md +25 -0
  79. package/runtime/pi/.codex/skills/push/SKILL.md +25 -0
  80. package/runtime/pi/.codex/skills/quest/SKILL.md +77 -0
  81. package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +25 -0
  82. package/runtime/pi/.codex/skills/reflect/SKILL.md +41 -0
  83. package/runtime/pi/.codex/skills/review-pr/SKILL.md +41 -0
  84. package/runtime/pi/.codex/skills/save/SKILL.md +62 -0
  85. package/runtime/pi/.codex/skills/scroll/SKILL.md +168 -0
  86. package/runtime/pi/.codex/skills/scroll/agents/openai.yaml +4 -0
  87. package/runtime/pi/.codex/skills/scroll/assets/shell.html +542 -0
  88. package/runtime/pi/.codex/skills/search/SKILL.md +56 -0
  89. package/runtime/pi/.codex/skills/session-view/SKILL.md +25 -0
  90. package/runtime/pi/.codex/skills/setup/SKILL.md +25 -0
  91. package/runtime/pi/.codex/skills/summon/SKILL.md +41 -0
  92. package/runtime/pi/.codex/skills/sync-repos/SKILL.md +25 -0
  93. package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +25 -0
  94. package/runtime/pi/.codex/skills/telemetry/SKILL.md +25 -0
  95. package/runtime/pi/.codex/skills/test/SKILL.md +41 -0
  96. package/runtime/pi/.codex/skills/the-spiral/SKILL.md +84 -0
  97. package/runtime/pi/.codex/skills/thread/SKILL.md +25 -0
  98. package/runtime/pi/.codex/skills/todo/SKILL.md +41 -0
  99. package/runtime/pi/.codex/skills/tui-design/SKILL.md +41 -0
  100. package/runtime/pi/.codex/skills/tutorial/SKILL.md +41 -0
  101. package/runtime/pi/.codex/skills/update/SKILL.md +25 -0
  102. package/runtime/pi/.codex/skills/view/SKILL.md +156 -0
  103. package/runtime/pi/.codex/skills/view/agents/openai.yaml +4 -0
  104. package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +221 -0
  105. package/runtime/pi/.codex/skills/visual-explain/SKILL.md +41 -0
  106. package/runtime/pi/.codex/skills/wrap/SKILL.md +55 -0
  107. package/runtime/pi/.codex/spec-manifest.json +114 -0
  108. package/runtime/pi/.pi/APPEND_SYSTEM.md +255 -0
  109. package/runtime/pi/.pi/extensions/egregore.ts +324 -0
  110. package/runtime/pi/.pi/settings.json +6 -0
  111. package/runtime/pi/.pi/spec-manifest.json +12 -0
  112. package/runtime/pi/AGENTS.md +350 -0
  113. package/runtime/pi/bin/activity-data.sh +242 -0
  114. package/runtime/pi/bin/agent.sh +677 -0
  115. package/runtime/pi/bin/codex-install-skills.sh +78 -0
  116. package/runtime/pi/bin/codex-render-spec.mjs +394 -0
  117. package/runtime/pi/bin/codex-session-start.sh +188 -0
  118. package/runtime/pi/bin/codex-skill-render.mjs +323 -0
  119. package/runtime/pi/bin/codex-sync-skills.sh +227 -0
  120. package/runtime/pi/bin/dashboard-data.sh +178 -0
  121. package/runtime/pi/bin/graph-batch.sh +60 -0
  122. package/runtime/pi/bin/graph-op.sh +431 -0
  123. package/runtime/pi/bin/graph-wal.sh +228 -0
  124. package/runtime/pi/bin/graph.sh +177 -0
  125. package/runtime/pi/bin/handoff-pr-backfill.sh +86 -0
  126. package/runtime/pi/bin/handoff-run.sh +581 -0
  127. package/runtime/pi/bin/handoff-save-egregore.sh +136 -0
  128. package/runtime/pi/bin/index-handoff.sh +312 -0
  129. package/runtime/pi/bin/lib/artifact-id.sh +46 -0
  130. package/runtime/pi/bin/lib/config.sh +71 -0
  131. package/runtime/pi/bin/lib/context.sh +542 -0
  132. package/runtime/pi/bin/lib/dashboard-artifact.sh +142 -0
  133. package/runtime/pi/bin/lib/ensure-develop.sh +183 -0
  134. package/runtime/pi/bin/lib/git-sync.sh +288 -0
  135. package/runtime/pi/bin/lib/greeting.sh +340 -0
  136. package/runtime/pi/bin/lib/hash.sh +13 -0
  137. package/runtime/pi/bin/lib/identity.sh +174 -0
  138. package/runtime/pi/bin/lib/metrics.sh +374 -0
  139. package/runtime/pi/bin/lib/permissions.sh +106 -0
  140. package/runtime/pi/bin/lib/time.sh +56 -0
  141. package/runtime/pi/bin/lib/worktree-links.sh +54 -0
  142. package/runtime/pi/bin/notify.sh +207 -0
  143. package/runtime/pi/bin/pi-branch-policy.mjs +15 -0
  144. package/runtime/pi/bin/pi-product-workflows.mjs +324 -0
  145. package/runtime/pi/bin/pi-render-spec.mjs +114 -0
  146. package/runtime/pi/bin/pi-session-start.sh +24 -0
  147. package/runtime/pi/bin/publish-artifact.sh +201 -0
  148. package/runtime/pi/bin/publish-references.sh +144 -0
  149. package/runtime/pi/bin/repo-state.sh +99 -0
  150. package/runtime/pi/bin/telemetry.sh +391 -0
  151. package/runtime/pi/bin/worktree-create.sh +118 -0
  152. package/runtime/pi/bin/worktree-remove.sh +50 -0
  153. package/runtime/pi/bin/worktree.sh +198 -0
  154. package/runtime/pi/manifest.json +176 -0
@@ -0,0 +1,201 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # publish-artifact.sh — Generate HTML artifact + upload to API
5
+ # Usage: publish-artifact.sh <type> <file> [--title "..."] [--author "..."] [--description "..."] [--id "..."] [--raw-html] [--no-references]
6
+ #
7
+ # Connected mode (API key present): publishes to /api/artifacts/publish (permanent, org-scoped)
8
+ # OSS mode (no API key): publishes to /api/artifacts/share (ephemeral, 7-day TTL)
9
+ #
10
+ # --id <slug>: stable artifact ID — re-publishing with the same ID upserts the content
11
+ # at the same URL (e.g. egregore.xyz/view/{org}/board). Connected mode only;
12
+ # ignored in OSS mode. Must be 1-50 chars, alphanumeric/hyphen/underscore.
13
+ #
14
+ # --raw-html: Skip the egregore-artifacts render step and upload <file> directly.
15
+ # Use for already-rendered HTML attachments referenced from a handoff.
16
+ #
17
+ # --no-references: Skip the depth-1 auto-publish of backtick-referenced memory files.
18
+ # Set automatically when publish-references.sh invokes us for a child,
19
+ # preventing recursion.
20
+ #
21
+ # Outputs artifact URL on success, exits silently on failure.
22
+ # Designed for fire-and-forget use: `bash bin/publish-artifact.sh handoff file.md &`
23
+
24
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
25
+ CONFIG="$SCRIPT_DIR/egregore.json"
26
+
27
+ # --- Parse arguments ---
28
+ TYPE=""
29
+ FILE=""
30
+ TITLE=""
31
+ AUTHOR=""
32
+ DESCRIPTION=""
33
+ ARTIFACT_ID=""
34
+ RAW_HTML=0
35
+ SKIP_REFERENCES=0
36
+ PAIR=""
37
+
38
+ while [[ $# -gt 0 ]]; do
39
+ case "$1" in
40
+ --title) TITLE="$2"; shift 2 ;;
41
+ --author) AUTHOR="$2"; shift 2 ;;
42
+ --description) DESCRIPTION="$2"; shift 2 ;;
43
+ --id) ARTIFACT_ID="$2"; shift 2 ;;
44
+ --pair) PAIR="$2"; shift 2 ;;
45
+ --raw-html) RAW_HTML=1; shift ;;
46
+ --no-references) SKIP_REFERENCES=1; shift ;;
47
+ *)
48
+ if [ -z "$TYPE" ]; then
49
+ TYPE="$1"
50
+ elif [ -z "$FILE" ]; then
51
+ FILE="$1"
52
+ fi
53
+ shift ;;
54
+ esac
55
+ done
56
+
57
+ if [ -z "$TYPE" ] || [ -z "$FILE" ]; then
58
+ echo "Usage: publish-artifact.sh <type> <file> [--title ...] [--author ...] [--description ...] [--id ...]" >&2
59
+ exit 1
60
+ fi
61
+
62
+ # Validate --id format if provided (matches API regex ^[a-zA-Z0-9_-]{1,50}$)
63
+ if [ -n "$ARTIFACT_ID" ] && ! [[ "$ARTIFACT_ID" =~ ^[a-zA-Z0-9_-]{1,50}$ ]]; then
64
+ echo "--id must be 1-50 chars, alphanumeric/hyphen/underscore only" >&2
65
+ exit 1
66
+ fi
67
+
68
+ if [ ! -f "$FILE" ]; then
69
+ echo "File not found: $FILE" >&2
70
+ exit 1
71
+ fi
72
+
73
+ # --- Load config ---
74
+ if [ -f "$SCRIPT_DIR/.env" ]; then
75
+ EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
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)}"
78
+ fi
79
+
80
+ API_URL="${EGREGORE_API_URL:-$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)}"
81
+ API_KEY="${EGREGORE_API_KEY:-}"
82
+ ORG_SLUG="$(jq -r '.slug // empty' "$CONFIG" 2>/dev/null)"
83
+ VIEW_BASE="https://egregore.xyz/view"
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
+
95
+ # Public relay for OSS share endpoint
96
+ RELAY_URL="https://egregore-production-55f2.up.railway.app"
97
+
98
+ # --- Prepare HTML ---
99
+ TMP_HTML="/tmp/egregore-artifacts/publish-$$.html"
100
+ mkdir -p /tmp/egregore-artifacts
101
+
102
+ if [ "$RAW_HTML" -eq 1 ]; then
103
+ # Upload the file as-is (used for pre-rendered HTML attachments).
104
+ cp "$FILE" "$TMP_HTML" 2>/dev/null || exit 0
105
+ else
106
+ # Pass --org-slug + --view-base so the renderer can emit clickable links
107
+ # for backtick `memory/*.{md,html}` references. Only when connected AND the
108
+ # slug is known — in OSS mode we leave them empty so rendering falls back
109
+ # to plain <code> and we don't produce dead links.
110
+ RENDER_ARGS=("$TYPE" "$FILE" --output "$TMP_HTML")
111
+ if [ -n "$API_KEY" ] && [ -n "$ORG_SLUG" ]; then
112
+ RENDER_ARGS+=(--org-slug "$ORG_SLUG" --view-base "$VIEW_BASE")
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
119
+
120
+ # Prefer the in-repo package copy when it's present AND its dependencies
121
+ # have been installed — that way local edits to packages/egregore-artifacts
122
+ # are exercised without waiting for an npm release. Fall back to the
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.
127
+ LOCAL_CLI="$SCRIPT_DIR/packages/egregore-artifacts/bin/cli.js"
128
+ if [ "${EGREGORE_USE_PUBLISHED:-0}" != "1" ] && [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
129
+ if ! node "$LOCAL_CLI" "${RENDER_ARGS[@]}" >/dev/null 2>&1; then
130
+ exit 0
131
+ fi
132
+ else
133
+ if ! npx egregore-artifacts@latest "${RENDER_ARGS[@]}" >/dev/null 2>&1; then
134
+ exit 0
135
+ fi
136
+ fi
137
+ fi
138
+
139
+ if [ ! -f "$TMP_HTML" ]; then
140
+ exit 0
141
+ fi
142
+
143
+ # Default title from filename if not provided
144
+ if [ -z "$TITLE" ]; then
145
+ TITLE="$(basename "$FILE" | sed 's/\.[^.]*$//' | sed 's/[-_]/ /g')"
146
+ fi
147
+
148
+ # --- Upload ---
149
+ RESPONSE=""
150
+
151
+ if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
152
+ # Connected mode: permanent, org-scoped
153
+ RESPONSE=$(curl -s -X POST "${API_URL}/api/artifacts/publish" \
154
+ -H "Authorization: Bearer $API_KEY" \
155
+ -F "file=@${TMP_HTML}" \
156
+ -F "artifact_type=${TYPE}" \
157
+ -F "title=${TITLE}" \
158
+ -F "author=${AUTHOR}" \
159
+ -F "description=${DESCRIPTION}" \
160
+ -F "artifact_id=${ARTIFACT_ID}" \
161
+ --max-time 15 2>/dev/null) || true
162
+ else
163
+ # OSS mode: ephemeral, 7-day TTL
164
+ RESPONSE=$(curl -s -X POST "${RELAY_URL}/api/artifacts/share" \
165
+ -F "file=@${TMP_HTML}" \
166
+ -F "artifact_type=${TYPE}" \
167
+ -F "title=${TITLE}" \
168
+ -F "author=${AUTHOR}" \
169
+ -F "description=${DESCRIPTION}" \
170
+ --max-time 15 2>/dev/null) || true
171
+ fi
172
+
173
+ # Clean up
174
+ rm -f "$TMP_HTML"
175
+
176
+ # Output URL if successful
177
+ URL=""
178
+ if [ -n "$RESPONSE" ]; then
179
+ URL=$(echo "$RESPONSE" | jq -r '.url // empty' 2>/dev/null)
180
+ if [ -n "$URL" ]; then
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
189
+ fi
190
+ fi
191
+
192
+ # Depth-1 auto-publish of backtick-referenced memory files so the clickable
193
+ # links in the rendered parent resolve. Connected mode only; the helper exits
194
+ # silently in OSS mode. Skipped when:
195
+ # - parent publish failed (no URL),
196
+ # - --raw-html (HTML attachments don't embed markdown refs we'd parse),
197
+ # - --no-references (caller explicitly opts out / recursion guard).
198
+ if [ -n "$URL" ] && [ "$RAW_HTML" -eq 0 ] && [ "$SKIP_REFERENCES" -eq 0 ]; then
199
+ bash "$SCRIPT_DIR/bin/publish-references.sh" "$FILE" >/dev/null 2>&1 &
200
+ disown 2>/dev/null || true
201
+ fi
@@ -0,0 +1,144 @@
1
+ #!/bin/bash
2
+ set -uo pipefail
3
+
4
+ # publish-references.sh — Depth-1 auto-publish for referenced memory files.
5
+ #
6
+ # Usage: publish-references.sh <source-markdown-file>
7
+ #
8
+ # Reads the source markdown, extracts backtick-wrapped references to
9
+ # `memory/**/*.{md,html}` paths, and publishes each one in parallel with a
10
+ # deterministic artifact id (see bin/lib/artifact-id.sh). The deterministic id
11
+ # means the rendered parent view can construct a predictable link to each
12
+ # referenced file *before* this script finishes — so even a slight delay
13
+ # produces clickable links that resolve once the referenced publish completes.
14
+ #
15
+ # Connected mode only. Skips silently if EGREGORE_API_KEY is missing, because
16
+ # the OSS relay ignores artifact ids and would assign random slugs.
17
+ #
18
+ # Fire-and-forget: silent on errors, does not block the caller, bounded
19
+ # parallelism via EGREGORE_REF_PUBLISH_PARALLELISM (default 8).
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
22
+ SOURCE_FILE="${1:-}"
23
+
24
+ [ -n "$SOURCE_FILE" ] || exit 0
25
+ [ -f "$SOURCE_FILE" ] || exit 0
26
+
27
+ # --- Connected-mode check ---
28
+ API_KEY="${EGREGORE_API_KEY:-}"
29
+ if [ -z "$API_KEY" ] && [ -f "$SCRIPT_DIR/.env" ]; then
30
+ API_KEY="$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)"
31
+ fi
32
+ [ -n "$API_KEY" ] || exit 0
33
+
34
+ # --- Helpers ---
35
+ # shellcheck disable=SC1091
36
+ . "$SCRIPT_DIR/bin/lib/artifact-id.sh"
37
+
38
+ PARALLELISM="${EGREGORE_REF_PUBLISH_PARALLELISM:-8}"
39
+
40
+ GIT_ROOT="$(git -C "$(dirname "$SOURCE_FILE")" rev-parse --show-toplevel 2>/dev/null || echo "$SCRIPT_DIR")"
41
+
42
+ # Absolute, symlink-resolved path of the source file. Used below to compare
43
+ # each resolved ref against the source and skip self-references. Using
44
+ # symlink-resolved absolute paths means `memory/` as a symlink into a sibling
45
+ # repo (and macOS's `/var` → `/private/var`) compare correctly — basename
46
+ # comparison alone would falsely skip unrelated files that happen to share
47
+ # a filename (e.g. date-prefixed handoffs, README.md, index.md).
48
+ SOURCE_ABS="$(cd "$(dirname "$SOURCE_FILE")" 2>/dev/null && pwd -P)/$(basename "$SOURCE_FILE")"
49
+
50
+ # Infer artifact type from path — mirrors egregore-artifacts/bin/cli.js inferType.
51
+ infer_type() {
52
+ local fp="$1"
53
+ case "$fp" in
54
+ */quests/*) echo "quest" ;;
55
+ */handoffs/*) echo "handoff" ;;
56
+ *) echo "document" ;;
57
+ esac
58
+ }
59
+
60
+ # Resolve a backtick-referenced path to a real file on disk.
61
+ resolve_ref() {
62
+ local ref="$1"
63
+ local src_dir
64
+ src_dir="$(dirname "$SOURCE_FILE")"
65
+ # Candidates: source file's repo-root resolution, then git root, then cwd.
66
+ local candidates=(
67
+ "$src_dir/../../$ref"
68
+ "$GIT_ROOT/$ref"
69
+ "$ref"
70
+ )
71
+ local c
72
+ for c in "${candidates[@]}"; do
73
+ if [ -f "$c" ]; then
74
+ printf '%s' "$c"
75
+ return 0
76
+ fi
77
+ done
78
+ return 1
79
+ }
80
+
81
+ publish_one() {
82
+ local ref="$1"
83
+ local resolved
84
+ resolved="$(resolve_ref "$ref")" || return 0
85
+ [ -n "$resolved" ] || return 0
86
+
87
+ # Self-ref guard: skip refs that resolve to the source file itself.
88
+ # Compared as symlink-resolved absolute paths so symlinked memory layouts
89
+ # (and unrelated files with the same basename) are handled correctly.
90
+ local resolved_abs
91
+ resolved_abs="$(cd "$(dirname "$resolved")" 2>/dev/null && pwd -P)/$(basename "$resolved")"
92
+ if [ "$resolved_abs" = "$SOURCE_ABS" ]; then
93
+ return 0
94
+ fi
95
+
96
+ local id
97
+ id="$(artifact_id_from_path "$ref")" || return 0
98
+ [ -n "$id" ] || return 0
99
+
100
+ case "$ref" in
101
+ *.md)
102
+ local type
103
+ type="$(infer_type "$ref")"
104
+ bash "$SCRIPT_DIR/bin/publish-artifact.sh" "$type" "$resolved" --id "$id" --no-references >/dev/null 2>&1 || true
105
+ ;;
106
+ *.html)
107
+ bash "$SCRIPT_DIR/bin/publish-artifact.sh" document "$resolved" --id "$id" --raw-html --no-references >/dev/null 2>&1 || true
108
+ ;;
109
+ esac
110
+ }
111
+
112
+ # --- Extract refs, dedupe, publish in parallel ---
113
+ # grep -Eo prints each match on its own line; sed strips the surrounding
114
+ # backticks; sort -u dedupes. No dependency on GNU grep -P.
115
+ REFS="$(grep -Eo '`memory/[^`[:space:]]+\.(md|html)`' "$SOURCE_FILE" 2>/dev/null \
116
+ | sed 's/^`//; s/`$//' \
117
+ | sort -u)"
118
+
119
+ [ -n "$REFS" ] || exit 0
120
+
121
+ # Bounded parallelism — cap concurrent jobs at PARALLELISM.
122
+ # On bash ≥ 4 (`wait -n`) this is rolling parallelism. On bash 3.2 (macOS
123
+ # default /bin/bash), `wait -n` is unsupported and the `|| wait` fallback
124
+ # drains the whole batch before spawning the next — effectively batch-parallel
125
+ # of size PARALLELISM. Correct in both cases, just slower on bash 3.2.
126
+ active=0
127
+ while IFS= read -r ref; do
128
+ [ -n "$ref" ] || continue
129
+ # Self-reference filtering happens inside publish_one, after the ref is
130
+ # resolved to an absolute path — see the SOURCE_ABS check there.
131
+ publish_one "$ref" &
132
+ active=$((active + 1))
133
+ if [ "$active" -ge "$PARALLELISM" ]; then
134
+ if wait -n 2>/dev/null; then
135
+ active=$((active - 1))
136
+ else
137
+ wait
138
+ active=0
139
+ fi
140
+ fi
141
+ done <<< "$REFS"
142
+
143
+ wait 2>/dev/null || true
144
+ exit 0
@@ -0,0 +1,99 @@
1
+ #!/bin/bash
2
+ # repo-state.sh — Capture current branch state across all repos.
3
+ # Outputs a markdown table (## Repo State) for handoff files.
4
+ # Only includes repos on non-base branches or with uncommitted changes.
5
+ #
6
+ # Usage: bash bin/repo-state.sh [--no-pr]
7
+ # --no-pr Skip the `gh pr list` lookup per repo (~400–600ms each).
8
+ # PR column will be `—`. Useful on the hot path where a detached
9
+ # backfill will fill PR numbers in later.
10
+ # Outputs the markdown section to stdout. Empty output = nothing to report.
11
+ set -euo pipefail
12
+
13
+ NO_PR=0
14
+ while [ $# -gt 0 ]; do
15
+ case "$1" in
16
+ --no-pr) NO_PR=1; shift ;;
17
+ *) shift ;;
18
+ esac
19
+ done
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
22
+ CONFIG="$SCRIPT_DIR/egregore.json"
23
+ PARENT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
24
+
25
+ # Source config helpers for _get_base_branch
26
+ source "$SCRIPT_DIR/bin/lib/config.sh" 2>/dev/null || true
27
+
28
+ CORE_REPO=$(jq -r '.repo_name // "egregore"' "$CONFIG" 2>/dev/null)
29
+ GITHUB_ORG=$(jq -r '.github_org // empty' "$CONFIG" 2>/dev/null)
30
+ MANAGED_REPOS=$(jq -r '(.repos[]? // empty) | if type == "object" then .name else . end' "$CONFIG" 2>/dev/null)
31
+
32
+ ROWS=""
33
+
34
+ check_repo() {
35
+ local repo_name="$1"
36
+ local repo_dir="$2"
37
+ local base_branch="$3"
38
+
39
+ [ -d "$repo_dir/.git" ] || [ -f "$repo_dir/.git" ] || return 0
40
+
41
+ local branch
42
+ branch=$(git -C "$repo_dir" branch --show-current 2>/dev/null || echo "")
43
+ [ -z "$branch" ] && return 0
44
+
45
+ local dirty=""
46
+ [ -n "$(git -C "$repo_dir" status --porcelain 2>/dev/null | head -1)" ] && dirty="yes"
47
+
48
+ # Skip if on base branch with no changes
49
+ if [ "$branch" = "$base_branch" ] && [ -z "$dirty" ]; then
50
+ return 0
51
+ fi
52
+
53
+ # Count commits ahead of base
54
+ local ahead=0
55
+ ahead=$(git -C "$repo_dir" rev-list "origin/${base_branch}..HEAD" --count 2>/dev/null || echo "0")
56
+
57
+ # Skip if on base branch, no dirty files, no commits ahead
58
+ if [ "$branch" = "$base_branch" ] && [ -z "$dirty" ] && [ "$ahead" = "0" ]; then
59
+ return 0
60
+ fi
61
+
62
+ # Check for open PR (skipped with --no-pr; a detached backfill fills it in)
63
+ local pr="—"
64
+ if [ "$NO_PR" = "0" ] && command -v gh &>/dev/null && [ -n "$GITHUB_ORG" ]; then
65
+ local pr_num
66
+ pr_num=$(gh pr list --repo "$GITHUB_ORG/$repo_name" --head "$branch" --json number -q '.[0].number' 2>/dev/null || true)
67
+ [ -n "$pr_num" ] && pr="#$pr_num"
68
+ fi
69
+
70
+ ROWS="${ROWS}| ${repo_name} | ${branch} | ${pr} | ${base_branch} |\n"
71
+ }
72
+
73
+ # Check core repo
74
+ CORE_BASE="develop"
75
+ if [ -f "$CONFIG" ]; then
76
+ # Core repo base: check if develop exists, otherwise main
77
+ if git -C "$SCRIPT_DIR" show-ref --verify --quiet refs/remotes/origin/develop 2>/dev/null; then
78
+ CORE_BASE="develop"
79
+ else
80
+ CORE_BASE="main"
81
+ fi
82
+ fi
83
+ check_repo "$CORE_REPO" "$SCRIPT_DIR" "$CORE_BASE"
84
+
85
+ # Check managed repos
86
+ for REPO in $MANAGED_REPOS; do
87
+ REPO_DIR="$PARENT_DIR/$REPO"
88
+ BASE=$(_get_base_branch "$REPO" 2>/dev/null || echo "develop")
89
+ check_repo "$REPO" "$REPO_DIR" "$BASE"
90
+ done
91
+
92
+ # Output
93
+ if [ -n "$ROWS" ]; then
94
+ echo "## Repo State"
95
+ echo ""
96
+ echo "| Repo | Branch | PR | Base |"
97
+ echo "|------|--------|----|------|"
98
+ printf '%b' "$ROWS"
99
+ fi