create-egregore 0.19.5 → 0.19.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/egregore-launcher.js +407 -25
- package/bin/cli.js +34 -20
- package/lib/local.js +21 -5
- package/lib/pi-runtime.js +186 -0
- package/lib/setup.js +56 -11
- package/lib/ui.js +1 -1
- package/package.json +7 -5
- package/runtime/codex/.codex/spec-manifest.json +1 -1
- package/runtime/codex/AGENTS.md +7 -2
- package/runtime/codex/bin/codex-render-spec.mjs +6 -1
- package/runtime/codex/bin/codex-session-start.sh +5 -59
- package/runtime/codex/bin/codex-skill-render.mjs +7 -5
- package/runtime/codex/bin/lib/context.sh +8 -1
- package/runtime/codex/bin/lib/greeting.sh +12 -108
- package/runtime/codex/bin/lib/metrics.sh +374 -0
- package/runtime/codex/bin/publish-artifact.sh +14 -0
- package/runtime/codex/bin/settings.sh +274 -0
- package/runtime/codex/manifest.json +2 -0
- package/runtime/pi/.codex/config.toml +15 -0
- package/runtime/pi/.codex/hooks/branch-guard.js +242 -0
- package/runtime/pi/.codex/hooks/search-hint.js +65 -0
- package/runtime/pi/.codex/hooks.json +30 -0
- package/runtime/pi/.codex/skills/activity/SKILL.md +70 -0
- package/runtime/pi/.codex/skills/add/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/announce/SKILL.md +54 -0
- package/runtime/pi/.codex/skills/answer/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/archive/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/ask/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/branch/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/checkup/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/commit/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/contribute/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dark-mode/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +74 -0
- package/runtime/pi/.codex/skills/delete-user/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/emissary/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/env/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/handoff/SKILL.md +67 -0
- package/runtime/pi/.codex/skills/harvest/SKILL.md +107 -0
- package/runtime/pi/.codex/skills/ingest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-google/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/invite/SKILL.md +40 -0
- package/runtime/pi/.codex/skills/issue/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/me/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/meeting/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/minion/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/note/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/onboarding/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pr/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/project/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/pull/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/push/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/quest/SKILL.md +77 -0
- package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/reflect/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/review-pr/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/save/SKILL.md +62 -0
- package/runtime/pi/.codex/skills/scroll/SKILL.md +168 -0
- package/runtime/pi/.codex/skills/scroll/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/scroll/assets/shell.html +542 -0
- package/runtime/pi/.codex/skills/search/SKILL.md +56 -0
- package/runtime/pi/.codex/skills/session-view/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/setup/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/summon/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/sync-repos/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/telemetry/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/test/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/pi/.codex/skills/thread/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/todo/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tui-design/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/tutorial/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/update/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/view/SKILL.md +156 -0
- package/runtime/pi/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/pi/.codex/skills/visual-explain/SKILL.md +41 -0
- package/runtime/pi/.codex/skills/wrap/SKILL.md +55 -0
- package/runtime/pi/.codex/spec-manifest.json +114 -0
- package/runtime/pi/.pi/APPEND_SYSTEM.md +255 -0
- package/runtime/pi/.pi/extensions/egregore.ts +324 -0
- package/runtime/pi/.pi/settings.json +6 -0
- package/runtime/pi/.pi/spec-manifest.json +12 -0
- package/runtime/pi/AGENTS.md +350 -0
- package/runtime/pi/bin/activity-data.sh +242 -0
- package/runtime/pi/bin/agent.sh +677 -0
- package/runtime/pi/bin/codex-install-skills.sh +78 -0
- package/runtime/pi/bin/codex-render-spec.mjs +394 -0
- package/runtime/pi/bin/codex-session-start.sh +188 -0
- package/runtime/pi/bin/codex-skill-render.mjs +323 -0
- package/runtime/pi/bin/codex-sync-skills.sh +227 -0
- package/runtime/pi/bin/dashboard-data.sh +178 -0
- package/runtime/pi/bin/graph-batch.sh +60 -0
- package/runtime/pi/bin/graph-op.sh +431 -0
- package/runtime/pi/bin/graph-wal.sh +228 -0
- package/runtime/pi/bin/graph.sh +177 -0
- package/runtime/pi/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/pi/bin/handoff-run.sh +581 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +136 -0
- package/runtime/pi/bin/index-handoff.sh +312 -0
- package/runtime/pi/bin/lib/artifact-id.sh +46 -0
- package/runtime/pi/bin/lib/config.sh +71 -0
- package/runtime/pi/bin/lib/context.sh +542 -0
- package/runtime/pi/bin/lib/dashboard-artifact.sh +142 -0
- package/runtime/pi/bin/lib/ensure-develop.sh +183 -0
- package/runtime/pi/bin/lib/git-sync.sh +288 -0
- package/runtime/pi/bin/lib/greeting.sh +340 -0
- package/runtime/pi/bin/lib/hash.sh +13 -0
- package/runtime/pi/bin/lib/identity.sh +174 -0
- package/runtime/pi/bin/lib/metrics.sh +374 -0
- package/runtime/pi/bin/lib/permissions.sh +106 -0
- package/runtime/pi/bin/lib/time.sh +56 -0
- package/runtime/pi/bin/lib/worktree-links.sh +54 -0
- package/runtime/pi/bin/notify.sh +207 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +15 -0
- package/runtime/pi/bin/pi-product-workflows.mjs +324 -0
- package/runtime/pi/bin/pi-render-spec.mjs +114 -0
- package/runtime/pi/bin/pi-session-start.sh +24 -0
- package/runtime/pi/bin/publish-artifact.sh +201 -0
- package/runtime/pi/bin/publish-references.sh +144 -0
- package/runtime/pi/bin/repo-state.sh +99 -0
- package/runtime/pi/bin/telemetry.sh +391 -0
- package/runtime/pi/bin/worktree-create.sh +118 -0
- package/runtime/pi/bin/worktree-remove.sh +50 -0
- package/runtime/pi/bin/worktree.sh +198 -0
- package/runtime/pi/manifest.json +176 -0
|
@@ -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
|