create-egregore 0.19.8 → 0.19.11
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/lib/local.js +11 -1
- package/lib/setup.js +33 -0
- package/package.json +1 -1
- package/runtime/codex/.codex/hooks/branch-guard.js +242 -34
- package/runtime/codex/.codex/skills/activity/SKILL.md +18 -6
- package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +90 -55
- package/runtime/codex/.codex/skills/deploy-bridge/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/handoff/SKILL.md +6 -2
- package/runtime/codex/.codex/skills/save/SKILL.md +21 -3
- package/runtime/codex/.codex/skills/scroll/SKILL.md +54 -3
- package/runtime/codex/.codex/skills/task/SKILL.md +25 -0
- package/runtime/codex/.codex/skills/tui-design/SKILL.md +1 -1
- package/runtime/codex/.codex/skills/wrap/SKILL.md +4 -1
- package/runtime/codex/.codex/spec-manifest.json +15 -3
- package/runtime/codex/AGENTS.md +45 -9
- package/runtime/codex/bin/activity-data.sh +1 -1
- package/runtime/codex/bin/agent.sh +66 -23
- package/runtime/codex/bin/attendant.sh +525 -0
- package/runtime/codex/bin/capture-reconcile.sh +67 -0
- package/runtime/codex/bin/capture-run.sh +341 -0
- package/runtime/codex/bin/codex-render-spec.mjs +15 -4
- package/runtime/codex/bin/codex-session-start.sh +45 -3
- package/runtime/codex/bin/codex-skill-render.mjs +23 -4
- package/runtime/codex/bin/graph-op.sh +719 -49
- package/runtime/codex/bin/graph-wal.sh +3 -2
- package/runtime/codex/bin/handoff-run.sh +72 -0
- package/runtime/codex/bin/handoff-save-egregore.sh +51 -11
- package/runtime/codex/bin/index-handoff.sh +26 -17
- package/runtime/codex/bin/ingest-graph.sh +80 -0
- package/runtime/codex/bin/ingest-surface.html +429 -0
- package/runtime/codex/bin/ingest.py +614 -0
- package/runtime/codex/bin/ingest.sh +231 -0
- package/runtime/codex/bin/ingest_graph.py +776 -0
- package/runtime/codex/bin/ingest_surface.py +464 -0
- package/runtime/codex/bin/lib/git-sync.sh +2 -6
- package/runtime/codex/bin/lib/greeting.sh +157 -22
- package/runtime/codex/bin/lib/identity.sh +50 -29
- package/runtime/codex/bin/lib/noncode.sh +31 -0
- package/runtime/codex/bin/person.py +610 -0
- package/runtime/codex/bin/person.sh +448 -0
- package/runtime/codex/bin/session-autosave.sh +184 -0
- package/runtime/codex/bin/session-log.sh +199 -0
- package/runtime/codex/bin/settings.sh +1 -1
- package/runtime/codex/manifest.json +19 -1
- package/runtime/pi/.codex/hooks/branch-guard.js +242 -34
- package/runtime/pi/.codex/skills/activity/SKILL.md +18 -6
- package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +90 -55
- package/runtime/pi/.codex/skills/deploy-bridge/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/handoff/SKILL.md +6 -2
- package/runtime/pi/.codex/skills/save/SKILL.md +21 -3
- package/runtime/pi/.codex/skills/scroll/SKILL.md +54 -3
- package/runtime/pi/.codex/skills/task/SKILL.md +25 -0
- package/runtime/pi/.codex/skills/tui-design/SKILL.md +1 -1
- package/runtime/pi/.codex/skills/wrap/SKILL.md +4 -1
- package/runtime/pi/.codex/spec-manifest.json +15 -3
- package/runtime/pi/.pi/APPEND_SYSTEM.md +41 -5
- package/runtime/pi/.pi/extensions/egregore.ts +98 -8
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +45 -9
- package/runtime/pi/bin/activity-data.sh +1 -1
- package/runtime/pi/bin/agent.sh +66 -23
- package/runtime/pi/bin/attendant.sh +525 -0
- package/runtime/pi/bin/capture-reconcile.sh +67 -0
- package/runtime/pi/bin/capture-run.sh +341 -0
- package/runtime/pi/bin/codex-render-spec.mjs +15 -4
- package/runtime/pi/bin/codex-session-start.sh +45 -3
- package/runtime/pi/bin/codex-skill-render.mjs +23 -4
- package/runtime/pi/bin/graph-op.sh +719 -49
- package/runtime/pi/bin/graph-wal.sh +3 -2
- package/runtime/pi/bin/handoff-run.sh +72 -0
- package/runtime/pi/bin/handoff-save-egregore.sh +51 -11
- package/runtime/pi/bin/index-handoff.sh +26 -17
- package/runtime/pi/bin/ingest-graph.sh +80 -0
- package/runtime/pi/bin/ingest-surface.html +429 -0
- package/runtime/pi/bin/ingest.py +614 -0
- package/runtime/pi/bin/ingest.sh +231 -0
- package/runtime/pi/bin/ingest_graph.py +776 -0
- package/runtime/pi/bin/ingest_surface.py +464 -0
- package/runtime/pi/bin/lib/git-sync.sh +2 -6
- package/runtime/pi/bin/lib/greeting.sh +157 -22
- package/runtime/pi/bin/lib/identity.sh +50 -29
- package/runtime/pi/bin/lib/noncode.sh +31 -0
- package/runtime/pi/bin/person.py +610 -0
- package/runtime/pi/bin/person.sh +448 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +164 -4
- package/runtime/pi/bin/pi-product-workflows.mjs +31 -2
- package/runtime/pi/bin/publish-artifact.sh +14 -0
- package/runtime/pi/bin/session-autosave.sh +184 -0
- package/runtime/pi/bin/session-log.sh +199 -0
- package/runtime/pi/bin/settings.sh +274 -0
- package/runtime/pi/manifest.json +20 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# - First session welcome
|
|
15
15
|
#
|
|
16
16
|
# Inputs: SCRIPT_DIR, STATE_FILE, CONFIG, CTX_DIR, BRANCH, COMMITS_AHEAD,
|
|
17
|
-
# AUTHOR, LOCAL_MODE, MEMORY_SYNCED,
|
|
17
|
+
# AUTHOR, LOCAL_MODE, MEMORY_SYNCED, SAVED_BRANCH,
|
|
18
18
|
# HEALTH_*, FRAMEWORK_VERSION, TIME_OF_DAY, EGREGORE_SESSION_ID,
|
|
19
19
|
# FIRST_SESSION, DISPLAY_NAME_STATE, DASHBOARD_URL
|
|
20
20
|
|
|
@@ -67,7 +67,8 @@ echo "$SEPARATOR"
|
|
|
67
67
|
source "$SCRIPT_DIR/bin/lib/metrics.sh"
|
|
68
68
|
_render_momentum_board
|
|
69
69
|
|
|
70
|
-
# Pending questions addressed to you
|
|
70
|
+
# Pending questions and handoffs addressed to you. These are lightweight
|
|
71
|
+
# discovery beats; management stays in /answer and /activity.
|
|
71
72
|
PENDING_Q=$(cat "$CTX_DIR/pending_questions" 2>/dev/null || echo "[]")
|
|
72
73
|
PENDING_Q_COUNT=$(echo "$PENDING_Q" | jq 'length' 2>/dev/null || echo "0")
|
|
73
74
|
if [ "$PENDING_Q_COUNT" -gt 0 ] 2>/dev/null && [ "$PENDING_Q_COUNT" != "0" ]; then
|
|
@@ -83,6 +84,11 @@ if [ "$PENDING_Q_COUNT" -gt 0 ] 2>/dev/null && [ "$PENDING_Q_COUNT" != "0" ]; th
|
|
|
83
84
|
printf " ◐ %s pending %s — /answer to engage\n" "$PENDING_Q_COUNT" "$PQ_NOUN"
|
|
84
85
|
fi
|
|
85
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
|
|
86
92
|
|
|
87
93
|
# Show auto-save notice if work was committed from a previous branch
|
|
88
94
|
if [ -n "$SAVED_BRANCH" ]; then
|
|
@@ -114,14 +120,6 @@ if [ "$LOCAL_MODE" = "true" ]; then
|
|
|
114
120
|
else
|
|
115
121
|
printf " ✓ ready\n"
|
|
116
122
|
fi
|
|
117
|
-
|
|
118
|
-
# Managed repos on separate line
|
|
119
|
-
if [ -n "$REPOS_STATUS" ]; then
|
|
120
|
-
REPOS_COMPACT=$(printf '%s' "$REPOS_STATUS" | sed 's/^ ◇ //;s/^[[:space:]]*//' | paste -sd' ' - | sed 's/[[:space:]]*$//')
|
|
121
|
-
if [ -n "$REPOS_COMPACT" ]; then
|
|
122
|
-
printf " %s\n" "$REPOS_COMPACT"
|
|
123
|
-
fi
|
|
124
|
-
fi
|
|
125
123
|
fi
|
|
126
124
|
else
|
|
127
125
|
# Connected mode: check all services
|
|
@@ -151,30 +149,167 @@ else
|
|
|
151
149
|
F_PAD=$((LINE_WIDTH - FL_LEN - FR_LEN))
|
|
152
150
|
if [ "$F_PAD" -lt 1 ]; then F_PAD=1; fi
|
|
153
151
|
printf "%s%*s%s\n" "$FOOTER_LEFT" "$F_PAD" "" "$FOOTER_RIGHT"
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
# Autosave trail — background saves (Stop-hook, sweep, SessionEnd) since the
|
|
156
|
+
# last greeting. The ledger is machine-scoped; this is where sweep rescues of
|
|
157
|
+
# abandoned sessions become visible to the user.
|
|
158
|
+
AUTOSAVE_LOG="${EGREGORE_AUTOSAVE_LOG:-$HOME/.egregore/autosave.log}"
|
|
159
|
+
AUTOSAVE_SEEN="${AUTOSAVE_LOG}.seen"
|
|
160
|
+
if [ -f "$AUTOSAVE_LOG" ]; then
|
|
161
|
+
TOTAL_AS=$(grep -c '|autosave|' "$AUTOSAVE_LOG" 2>/dev/null || echo 0)
|
|
162
|
+
SEEN_AS=$(cat "$AUTOSAVE_SEEN" 2>/dev/null || echo 0)
|
|
163
|
+
case "$SEEN_AS" in ''|*[!0-9]*) SEEN_AS=0 ;; esac
|
|
164
|
+
if [ "$TOTAL_AS" -gt "$SEEN_AS" ]; then
|
|
165
|
+
NEW_AS=$((TOTAL_AS - SEEN_AS))
|
|
166
|
+
MERGED_AS=$(grep '|autosave|' "$AUTOSAVE_LOG" 2>/dev/null | tail -n "$NEW_AS" | grep -c '|merged|' || echo 0)
|
|
167
|
+
if [ "$MERGED_AS" -ge "$NEW_AS" ]; then
|
|
168
|
+
printf " ⟲ auto-saved %s non-coding save(s) → develop while you were away\n" "$NEW_AS"
|
|
169
|
+
else
|
|
170
|
+
printf " ⟲ auto-saved %s non-coding save(s) — %s merged, rest in open PRs\n" "$NEW_AS" "$MERGED_AS"
|
|
161
171
|
fi
|
|
162
172
|
fi
|
|
173
|
+
printf '%s' "$TOTAL_AS" > "$AUTOSAVE_SEEN" 2>/dev/null || true
|
|
163
174
|
fi
|
|
164
175
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
176
|
+
# Greeting links. Org config `pinned_links` in egregore.json replaces the
|
|
177
|
+
# default dashboard + board links. Entries are strings or {url, label}.
|
|
178
|
+
# (OSC 8 hyperlink — clickable text in supported terminals)
|
|
179
|
+
PINNED_LINKS=$(jq -c '.pinned_links // []' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "[]")
|
|
180
|
+
if [ "$(printf '%s' "$PINNED_LINKS" | jq 'length' 2>/dev/null || echo 0)" -gt 0 ]; then
|
|
181
|
+
printf '%s' "$PINNED_LINKS" | jq -r '.[] |
|
|
182
|
+
if type == "string" then " ◆ \(.)"
|
|
183
|
+
elif (.label // "") != "" then " ◆ \(.label): \(.url)"
|
|
184
|
+
else " ◆ \(.url)" end' 2>/dev/null
|
|
185
|
+
else
|
|
186
|
+
if [ -n "${DASHBOARD_URL:-}" ]; then
|
|
187
|
+
printf " ◆ %s\n" "$DASHBOARD_URL"
|
|
188
|
+
fi
|
|
169
189
|
|
|
170
|
-
if [ -n "${BOARD_URL:-}" ]; then
|
|
171
|
-
|
|
190
|
+
if [ -n "${BOARD_URL:-}" ]; then
|
|
191
|
+
printf " ◆ %s (board)\n" "$BOARD_URL"
|
|
192
|
+
fi
|
|
172
193
|
fi
|
|
173
194
|
|
|
174
195
|
if [ -n "${LOOM_DOCTOR_BRIEF:-}" ]; then
|
|
175
196
|
printf " %s\n" "$LOOM_DOCTOR_BRIEF"
|
|
176
197
|
fi
|
|
177
198
|
|
|
199
|
+
# --- Creator review gate: pending turns on owned scrolls/surfaces ---
|
|
200
|
+
# This is deliberately filesystem-only and fail-soft. The two environment seams
|
|
201
|
+
# make the scan safe to exercise without touching the instance memory repo.
|
|
202
|
+
_print_pending_scroll_turns() {
|
|
203
|
+
local memory_root="${EGREGORE_MEMORY_ROOT:-$SCRIPT_DIR/memory}"
|
|
204
|
+
local person="${EGREGORE_PERSON:-${AUTHOR:-}}"
|
|
205
|
+
local rows="" file slug owner count surface_file
|
|
206
|
+
|
|
207
|
+
if [ -z "$person" ] && [ -f "${STATE_FILE:-}" ]; then
|
|
208
|
+
person=$(jq -r '.github_username // .display_name // .name // empty' "$STATE_FILE" 2>/dev/null || true)
|
|
209
|
+
fi
|
|
210
|
+
[ -n "$person" ] || return 0
|
|
211
|
+
[ -d "$memory_root" ] || return 0
|
|
212
|
+
|
|
213
|
+
for file in "$memory_root"/scrolls/.events/*.jsonl; do
|
|
214
|
+
[ -f "$file" ] || continue
|
|
215
|
+
slug=$(basename "$file" .jsonl)
|
|
216
|
+
[[ "$slug" =~ ^[A-Za-z0-9._-]+$ ]] || continue
|
|
217
|
+
safe_slug=$(printf '%s' "$slug" | tr -d '\000-\037\177')
|
|
218
|
+
[ "$safe_slug" = "$slug" ] || continue
|
|
219
|
+
owner=$(sed -nE 's/^[[:space:]-]*(\*\*)?creator(\*\*)?[[:space:]]*:[[:space:]]*//p' "$memory_root/scrolls/$slug.md" 2>/dev/null | head -1 | sed 's/[[:space:]]*$//')
|
|
220
|
+
[ "$owner" = "$person" ] || continue
|
|
221
|
+
count=$(jq -s -r '
|
|
222
|
+
def event_id:
|
|
223
|
+
if (.turn | type) == "object" then .turn.id
|
|
224
|
+
elif (.turn | type) == "string" then .turn
|
|
225
|
+
else .id end;
|
|
226
|
+
def received($events):
|
|
227
|
+
[$events[] | select(.type == "turn-received")
|
|
228
|
+
| {id: event_id, answers: (.turn.answers // .answers // [])}
|
|
229
|
+
| select(.id != null)] | unique_by(.id);
|
|
230
|
+
def review_id: event_id;
|
|
231
|
+
def is_absorbed($events; $id):
|
|
232
|
+
any($events[]; .type == "version-published" and ((.absorbs // .version.absorbs // .record.absorbs // []) | index($id) != null));
|
|
233
|
+
def is_applied($events; $id):
|
|
234
|
+
any($events[]; .type == "turn-applied" and (event_id == $id));
|
|
235
|
+
def is_declined($events; $received; $id):
|
|
236
|
+
([$received[] | select(.id == $id)] | .[0]) as $turn |
|
|
237
|
+
([$events[] | select(.type == "turn-reviewed" and review_id == $id)] | .[0]) as $review |
|
|
238
|
+
if $review == null then false
|
|
239
|
+
else if (($turn.answers // []) | length) == 0 then $review.disposition == "declined"
|
|
240
|
+
else (($turn.answers // [])
|
|
241
|
+
| map(($review.answers // {})[.fork] // $review.disposition)
|
|
242
|
+
| map(select(. == "accepted")) | length) == 0
|
|
243
|
+
end
|
|
244
|
+
end;
|
|
245
|
+
. as $events
|
|
246
|
+
| ($events | received($events)) as $received
|
|
247
|
+
| [$received[] as $turn
|
|
248
|
+
| select((is_absorbed($events; $turn.id) | not))
|
|
249
|
+
| select((is_declined($events; $received; $turn.id) | not))
|
|
250
|
+
| select(if $mode == "scroll" then true else (is_applied($events; $turn.id) | not) end)]
|
|
251
|
+
| length
|
|
252
|
+
' --arg mode scroll "$file" 2>/dev/null) || continue
|
|
253
|
+
[[ "$count" =~ ^[0-9]+$ ]] || return 0
|
|
254
|
+
[ "$count" -gt 0 ] && rows+="${safe_slug}"$'\t'"${count}"$'\n'
|
|
255
|
+
done
|
|
256
|
+
|
|
257
|
+
for file in "$memory_root"/harvests/.events/*.jsonl; do
|
|
258
|
+
[ -f "$file" ] || continue
|
|
259
|
+
slug=$(basename "$file" .jsonl)
|
|
260
|
+
[[ "$slug" =~ ^[A-Za-z0-9._-]+$ ]] || continue
|
|
261
|
+
safe_slug=$(printf '%s' "$slug" | tr -d '\000-\037\177')
|
|
262
|
+
[ "$safe_slug" = "$slug" ] || continue
|
|
263
|
+
surface_file="$memory_root/harvests/$slug.json"
|
|
264
|
+
[ -f "$surface_file" ] || continue
|
|
265
|
+
owner=$(jq -r '.author // empty' "$surface_file" 2>/dev/null) || continue
|
|
266
|
+
[ "$owner" = "$person" ] || continue
|
|
267
|
+
count=$(jq -s -r '
|
|
268
|
+
def event_id:
|
|
269
|
+
if (.turn | type) == "object" then .turn.id
|
|
270
|
+
elif (.turn | type) == "string" then .turn
|
|
271
|
+
else .id end;
|
|
272
|
+
def received($events):
|
|
273
|
+
[$events[] | select(.type == "turn-received")
|
|
274
|
+
| {id: event_id, answers: (.turn.answers // .answers // [])}
|
|
275
|
+
| select(.id != null)] | unique_by(.id);
|
|
276
|
+
def review_id: event_id;
|
|
277
|
+
def is_absorbed($events; $id): false;
|
|
278
|
+
def is_applied($events; $id):
|
|
279
|
+
any($events[]; .type == "turn-applied" and (event_id == $id));
|
|
280
|
+
def is_declined($events; $received; $id):
|
|
281
|
+
([$received[] | select(.id == $id)] | .[0]) as $turn |
|
|
282
|
+
([$events[] | select(.type == "turn-reviewed" and review_id == $id)] | .[0]) as $review |
|
|
283
|
+
if $review == null then false
|
|
284
|
+
else if (($turn.answers // []) | length) == 0 then $review.disposition == "declined"
|
|
285
|
+
else (($turn.answers // [])
|
|
286
|
+
| map(($review.answers // {})[.fork] // $review.disposition)
|
|
287
|
+
| map(select(. == "accepted")) | length) == 0
|
|
288
|
+
end
|
|
289
|
+
end;
|
|
290
|
+
. as $events
|
|
291
|
+
| ($events | received($events)) as $received
|
|
292
|
+
| [$received[] as $turn
|
|
293
|
+
| select((is_applied($events; $turn.id) | not))
|
|
294
|
+
| select((is_declined($events; $received; $turn.id) | not))]
|
|
295
|
+
| length
|
|
296
|
+
' --arg mode harvest "$file" 2>/dev/null) || continue
|
|
297
|
+
[[ "$count" =~ ^[0-9]+$ ]] || return 0
|
|
298
|
+
[ "$count" -gt 0 ] && rows+="${safe_slug}"$'\t'"${count}"$'\n'
|
|
299
|
+
done
|
|
300
|
+
|
|
301
|
+
[ -n "$rows" ] || return 0
|
|
302
|
+
local summary total details
|
|
303
|
+
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
|
|
304
|
+
[ -n "$summary" ] || return 0
|
|
305
|
+
total=$(printf '%s\n' "$summary" | awk -F '\t' '{ total += $2 } END { print total + 0 }') || return 0
|
|
306
|
+
details=$(printf '%s\n' "$summary" | awk -F '\t' '{printf "%s%s (%s)", (NR == 1 ? "" : ", "), $1, $2}') || return 0
|
|
307
|
+
[ -n "$details" ] || return 0
|
|
308
|
+
printf " ⧖ %s pending turn(s) on your scrolls: %s\n" "$total" "$details"
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
_print_pending_scroll_turns
|
|
312
|
+
|
|
178
313
|
# Framework updates come through PRs to develop — no separate auto-update channel.
|
|
179
314
|
# The develop sync above already keeps framework files current.
|
|
180
315
|
# Use /update for manual upstream pulls when needed.
|
|
@@ -41,8 +41,16 @@ else
|
|
|
41
41
|
if [ -n "$GH_TOKEN" ]; then
|
|
42
42
|
GH_USER_JSON=$(curl -s -H "Authorization: token $GH_TOKEN" https://api.github.com/user --max-time 5 2>/dev/null || echo "")
|
|
43
43
|
GH_LOGIN=$(echo "$GH_USER_JSON" | jq -r '.login // empty' 2>/dev/null)
|
|
44
|
+
GH_ID=$(echo "$GH_USER_JSON" | jq -r '.id // empty' 2>/dev/null)
|
|
44
45
|
GH_NAME=$(echo "$GH_USER_JSON" | jq -r '.name // empty' 2>/dev/null)
|
|
46
|
+
GH_EMAIL=$(echo "$GH_USER_JSON" | jq -r '.email // empty' 2>/dev/null)
|
|
45
47
|
if [ -n "$GH_LOGIN" ]; then
|
|
48
|
+
GH_ID_JSON="null"
|
|
49
|
+
GH_PERSON_ID="github-login:$(echo "$GH_LOGIN" | tr '[:upper:]' '[:lower:]')"
|
|
50
|
+
if [[ "$GH_ID" =~ ^[0-9]+$ ]]; then
|
|
51
|
+
GH_ID_JSON="$GH_ID"
|
|
52
|
+
GH_PERSON_ID="github:$GH_ID"
|
|
53
|
+
fi
|
|
46
54
|
AUTHOR="$GH_LOGIN"
|
|
47
55
|
HEALTH_GITHUB="ok"
|
|
48
56
|
# Set repo-local config and save to state for next time
|
|
@@ -63,11 +71,19 @@ else
|
|
|
63
71
|
if [ "$HAS_ONBOARDING" = "unset" ]; then
|
|
64
72
|
# State file exists but no onboarding flag — set to false to trigger it
|
|
65
73
|
jq --arg u "$GH_LOGIN" --arg n "${GH_NAME:-$GH_LOGIN}" --arg ut "$USAGE_TYPE" \
|
|
66
|
-
|
|
74
|
+
--argjson gid "$GH_ID_JSON" --arg pid "$GH_PERSON_ID" --arg email "$GH_EMAIL" \
|
|
75
|
+
'.github_username = $u | .github_id = $gid | .person_id = $pid |
|
|
76
|
+
.github_name = $n | .name = $n |
|
|
77
|
+
(if $email != "" then .email = ($email | ascii_downcase) else . end) |
|
|
78
|
+
.onboarding_complete = false | .usage_type = $ut' "$STATE_FILE" > "$STATE_FILE.tmp" \
|
|
67
79
|
&& mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
68
80
|
else
|
|
69
81
|
jq --arg u "$GH_LOGIN" --arg n "${GH_NAME:-$GH_LOGIN}" --arg ut "$USAGE_TYPE" \
|
|
70
|
-
|
|
82
|
+
--argjson gid "$GH_ID_JSON" --arg pid "$GH_PERSON_ID" --arg email "$GH_EMAIL" \
|
|
83
|
+
'.github_username = $u | .github_id = $gid | .person_id = $pid |
|
|
84
|
+
.github_name = $n | .name = $n |
|
|
85
|
+
(if $email != "" then .email = ($email | ascii_downcase) else . end) |
|
|
86
|
+
.usage_type = $ut' "$STATE_FILE" > "$STATE_FILE.tmp" \
|
|
71
87
|
&& mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
72
88
|
fi
|
|
73
89
|
FIRST_SESSION="false"
|
|
@@ -77,39 +93,44 @@ else
|
|
|
77
93
|
GRAPH_PERSON=""
|
|
78
94
|
GRAPH_DISPLAY_NAME=""
|
|
79
95
|
GRAPH_PERSON=$(bash "$SCRIPT_DIR/bin/graph.sh" query \
|
|
80
|
-
"MATCH (p:Person
|
|
81
|
-
|
|
96
|
+
"MATCH (p:Person)
|
|
97
|
+
WHERE NOT coalesce(p.kind, '') IN ['external', 'identity_alias']
|
|
98
|
+
AND coalesce(p.status, 'active') = 'active'
|
|
99
|
+
AND p.ingestRef IS NULL
|
|
100
|
+
AND (p.github = \$github
|
|
101
|
+
OR (\$githubId <> '' AND coalesce(toString(p.githubId), '') = \$githubId)
|
|
102
|
+
OR toLower(\$github) IN [alias IN coalesce(p.githubAliases, []) | toLower(alias)])
|
|
103
|
+
RETURN p.name AS name" \
|
|
104
|
+
"$(jq -n --arg github "$GH_LOGIN" --arg githubId "$GH_ID" \
|
|
105
|
+
'{github: $github, githubId: $githubId}')" 2>/dev/null || echo "")
|
|
82
106
|
if echo "$GRAPH_PERSON" | jq -e '.values | length > 0' &>/dev/null; then
|
|
83
107
|
GRAPH_DISPLAY_NAME=$(echo "$GRAPH_PERSON" | jq -r '.values[0][0] // empty' 2>/dev/null)
|
|
84
108
|
# Existing team member — skip onboarding
|
|
85
|
-
|
|
86
|
-
{
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
STATEEOF
|
|
109
|
+
jq -n --arg github "$GH_LOGIN" --argjson githubId "$GH_ID_JSON" \
|
|
110
|
+
--arg personId "$GH_PERSON_ID" --arg githubName "${GH_NAME:-$GH_LOGIN}" \
|
|
111
|
+
--arg name "${GRAPH_DISPLAY_NAME:-${GH_NAME:-$GH_LOGIN}}" \
|
|
112
|
+
--arg displayName "${GRAPH_DISPLAY_NAME:-}" --arg email "$GH_EMAIL" \
|
|
113
|
+
--arg usageType "$USAGE_TYPE" \
|
|
114
|
+
'{
|
|
115
|
+
github_username: $github, github_id: $githubId, person_id: $personId,
|
|
116
|
+
github_name: $githubName, name: $name, display_name: $displayName,
|
|
117
|
+
email: (if $email == "" then null else ($email | ascii_downcase) end),
|
|
118
|
+
onboarding_complete: true, usage_type: $usageType,
|
|
119
|
+
session_tracking: true, transcript_sharing: true, telemetry: true,
|
|
120
|
+
contact_preference: "all", telemetry_noticed: true
|
|
121
|
+
}' > "$STATE_FILE"
|
|
100
122
|
FIRST_SESSION="false"
|
|
101
123
|
else
|
|
102
124
|
# Genuinely new user — trigger onboarding
|
|
103
|
-
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
STATEEOF
|
|
125
|
+
jq -n --arg github "$GH_LOGIN" --argjson githubId "$GH_ID_JSON" \
|
|
126
|
+
--arg personId "$GH_PERSON_ID" --arg githubName "${GH_NAME:-$GH_LOGIN}" \
|
|
127
|
+
--arg email "$GH_EMAIL" --arg usageType "$USAGE_TYPE" \
|
|
128
|
+
'{
|
|
129
|
+
github_username: $github, github_id: $githubId, person_id: $personId,
|
|
130
|
+
github_name: $githubName, name: $githubName,
|
|
131
|
+
email: (if $email == "" then null else ($email | ascii_downcase) end),
|
|
132
|
+
onboarding_complete: false, usage_type: $usageType, first_session: true
|
|
133
|
+
}' > "$STATE_FILE"
|
|
113
134
|
FIRST_SESSION="true"
|
|
114
135
|
fi
|
|
115
136
|
fi
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# noncode.sh — shared "non-coding change" classifier for auto-merge decisions.
|
|
3
|
+
#
|
|
4
|
+
# The org rule: non-coding PRs auto-merge to develop; code goes to review.
|
|
5
|
+
# Non-coding means:
|
|
6
|
+
# - any .md file, anywhere
|
|
7
|
+
# - anything under content directories (artifacts/, docs/, .threads/) —
|
|
8
|
+
# html/css/images/design bundles there are authored content, not shipped code
|
|
9
|
+
# - session-state droppings (.egregore-worktree-tty)
|
|
10
|
+
# Everything else — bin/, api/, packages/, .claude/, site 2/, root config — is
|
|
11
|
+
# code and stays open for review.
|
|
12
|
+
#
|
|
13
|
+
# Sourced by handoff-save-egregore.sh, session-autosave.sh, agent.sh, and the
|
|
14
|
+
# /save skill. Keep the policy HERE — call sites must not grow their own.
|
|
15
|
+
|
|
16
|
+
# noncode_filter — reads paths on stdin, prints the first code-bearing path.
|
|
17
|
+
# Empty output = everything is non-coding.
|
|
18
|
+
noncode_filter() {
|
|
19
|
+
grep -Ev '\.md$' \
|
|
20
|
+
| grep -Ev '^(artifacts|docs|\.threads)/' \
|
|
21
|
+
| grep -Ev '^\.egregore-worktree-tty$' \
|
|
22
|
+
| head -1 || true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# noncode_blockers [base-ref] [repo-dir] — first code-bearing path committed
|
|
26
|
+
# on HEAD relative to base (three-dot: only our side of the diff).
|
|
27
|
+
# Empty output = the branch is non-coding and safe to auto-merge.
|
|
28
|
+
noncode_blockers() {
|
|
29
|
+
local base="${1:-origin/develop}" dir="${2:-.}"
|
|
30
|
+
git -C "$dir" diff "$base...HEAD" --name-only 2>/dev/null | noncode_filter
|
|
31
|
+
}
|