create-egregore 0.19.21 → 0.19.23

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 (229) hide show
  1. package/assets/egregore-launcher.js +29 -3
  2. package/bin/cli.js +3 -4
  3. package/lib/auth.js +3 -4
  4. package/lib/path-lookup.js +59 -0
  5. package/lib/setup.js +52 -6
  6. package/package.json +2 -2
  7. package/runtime/codex/.claude/context/notification-consent.md +66 -0
  8. package/runtime/codex/.codex/hooks/branch-guard.js +14 -3
  9. package/runtime/codex/.codex/skills/add/SKILL.md +8 -4
  10. package/runtime/codex/.codex/skills/announce/SKILL.md +21 -8
  11. package/runtime/codex/.codex/skills/answer/SKILL.md +8 -4
  12. package/runtime/codex/.codex/skills/archive/SKILL.md +8 -4
  13. package/runtime/codex/.codex/skills/ask/SKILL.md +14 -6
  14. package/runtime/codex/.codex/skills/audit/SKILL.md +29 -0
  15. package/runtime/codex/.codex/skills/autosave/SKILL.md +29 -0
  16. package/runtime/codex/.codex/skills/branch/SKILL.md +8 -4
  17. package/runtime/codex/.codex/skills/checkup/SKILL.md +8 -4
  18. package/runtime/codex/.codex/skills/commit/SKILL.md +8 -4
  19. package/runtime/codex/.codex/skills/contribute/SKILL.md +8 -4
  20. package/runtime/codex/.codex/skills/dark-mode/SKILL.md +8 -4
  21. package/runtime/codex/.codex/skills/delete-user/SKILL.md +8 -4
  22. package/runtime/codex/.codex/skills/demo-mode/SKILL.md +29 -0
  23. package/runtime/codex/.codex/skills/deploy-bridge/SKILL.md +8 -4
  24. package/runtime/codex/.codex/skills/design/SKILL.md +29 -0
  25. package/runtime/codex/.codex/skills/egregore-voice/SKILL.md +8 -4
  26. package/runtime/codex/.codex/skills/emissary/SKILL.md +8 -4
  27. package/runtime/codex/.codex/skills/env/SKILL.md +8 -4
  28. package/runtime/codex/.codex/skills/handoff/SKILL.md +81 -10
  29. package/runtime/codex/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
  30. package/runtime/codex/.codex/skills/harvest/SKILL.md +30 -6
  31. package/runtime/codex/.codex/skills/ingest/SKILL.md +8 -4
  32. package/runtime/codex/.codex/skills/ingest-google/SKILL.md +8 -4
  33. package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +8 -4
  34. package/runtime/codex/.codex/skills/invite/SKILL.md +6 -2
  35. package/runtime/codex/.codex/skills/issue/SKILL.md +8 -4
  36. package/runtime/codex/.codex/skills/me/SKILL.md +8 -4
  37. package/runtime/codex/.codex/skills/meeting/SKILL.md +8 -4
  38. package/runtime/codex/.codex/skills/minion/SKILL.md +8 -4
  39. package/runtime/codex/.codex/skills/mock/SKILL.md +29 -0
  40. package/runtime/codex/.codex/skills/note/SKILL.md +8 -4
  41. package/runtime/codex/.codex/skills/onboarding/SKILL.md +8 -4
  42. package/runtime/codex/.codex/skills/pr/SKILL.md +8 -4
  43. package/runtime/codex/.codex/skills/product-voice/SKILL.md +29 -0
  44. package/runtime/codex/.codex/skills/project/SKILL.md +8 -4
  45. package/runtime/codex/.codex/skills/pull/SKILL.md +8 -4
  46. package/runtime/codex/.codex/skills/push/SKILL.md +8 -4
  47. package/runtime/codex/.codex/skills/quest/SKILL.md +6 -3
  48. package/runtime/codex/.codex/skills/quest-suggest/SKILL.md +8 -4
  49. package/runtime/codex/.codex/skills/reflect/SKILL.md +8 -4
  50. package/runtime/codex/.codex/skills/review-pr/SKILL.md +8 -4
  51. package/runtime/codex/.codex/skills/save/SKILL.md +6 -4
  52. package/runtime/codex/.codex/skills/scroll/SKILL.md +92 -23
  53. package/runtime/codex/.codex/skills/scroll/assets/shell.html +381 -52
  54. package/runtime/codex/.codex/skills/session-view/SKILL.md +8 -4
  55. package/runtime/codex/.codex/skills/setup/SKILL.md +8 -4
  56. package/runtime/codex/.codex/skills/summon/SKILL.md +8 -4
  57. package/runtime/codex/.codex/skills/sync-repos/SKILL.md +8 -4
  58. package/runtime/codex/.codex/skills/task/SKILL.md +9 -5
  59. package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
  60. package/runtime/codex/.codex/skills/telegram-connect/SKILL.md +8 -4
  61. package/runtime/codex/.codex/skills/telemetry/SKILL.md +8 -4
  62. package/runtime/codex/.codex/skills/test/SKILL.md +8 -4
  63. package/runtime/codex/.codex/skills/thread/SKILL.md +8 -4
  64. package/runtime/codex/.codex/skills/todo/SKILL.md +8 -4
  65. package/runtime/codex/.codex/skills/tui-design/SKILL.md +8 -4
  66. package/runtime/codex/.codex/skills/tutorial/SKILL.md +8 -4
  67. package/runtime/codex/.codex/skills/update/SKILL.md +8 -4
  68. package/runtime/codex/.codex/skills/visual-explain/SKILL.md +8 -4
  69. package/runtime/codex/.codex/spec-manifest.json +4 -4
  70. package/runtime/codex/AGENTS.md +36 -14
  71. package/runtime/codex/bin/activity-data.sh +1 -1
  72. package/runtime/codex/bin/agent.sh +38 -19
  73. package/runtime/codex/bin/attendant.sh +8 -2
  74. package/runtime/codex/bin/autosave.sh +1 -1
  75. package/runtime/codex/bin/capture-reconcile.sh +8 -6
  76. package/runtime/codex/bin/capture-run.sh +1 -1
  77. package/runtime/codex/bin/codex-install-skills.sh +1 -1
  78. package/runtime/codex/bin/codex-render-spec.mjs +12 -5
  79. package/runtime/codex/bin/codex-session-start.sh +1 -1
  80. package/runtime/codex/bin/codex-skill-render.mjs +5 -0
  81. package/runtime/codex/bin/codex-sync-skills.sh +9 -5
  82. package/runtime/codex/bin/dashboard-data.sh +1 -1
  83. package/runtime/codex/bin/graph-batch.sh +1 -1
  84. package/runtime/codex/bin/graph-op.sh +1 -1
  85. package/runtime/codex/bin/graph-wal.sh +1 -1
  86. package/runtime/codex/bin/graph.sh +1 -1
  87. package/runtime/codex/bin/handoff-pr-backfill.sh +1 -1
  88. package/runtime/codex/bin/handoff-run.sh +117 -119
  89. package/runtime/codex/bin/handoff-save-egregore.sh +62 -32
  90. package/runtime/codex/bin/index-handoff.sh +3 -2
  91. package/runtime/codex/bin/ingest-graph.sh +1 -1
  92. package/runtime/codex/bin/ingest.sh +1 -1
  93. package/runtime/codex/bin/lib/artifact-id.sh +1 -1
  94. package/runtime/codex/bin/lib/config.sh +56 -20
  95. package/runtime/codex/bin/lib/context.sh +7 -1
  96. package/runtime/codex/bin/lib/ensure-develop.sh +1 -1
  97. package/runtime/codex/bin/lib/git-sync.sh +145 -59
  98. package/runtime/codex/bin/lib/greeting.sh +14 -0
  99. package/runtime/codex/bin/lib/hash.sh +1 -1
  100. package/runtime/codex/bin/lib/noncode.sh +1 -1
  101. package/runtime/codex/bin/lib/time.sh +1 -1
  102. package/runtime/codex/bin/notify.sh +492 -153
  103. package/runtime/codex/bin/person.sh +1 -1
  104. package/runtime/codex/bin/publish-artifact.sh +64 -8
  105. package/runtime/codex/bin/publish-references.sh +1 -1
  106. package/runtime/codex/bin/repo-state.sh +7 -10
  107. package/runtime/codex/bin/search.sh +1 -1
  108. package/runtime/codex/bin/session-autosave.sh +1 -1
  109. package/runtime/codex/bin/session-log.sh +1 -1
  110. package/runtime/codex/bin/settings.sh +32 -2
  111. package/runtime/codex/bin/telemetry.sh +1 -1
  112. package/runtime/codex/bin/worktree-create.sh +14 -4
  113. package/runtime/codex/bin/worktree-remove.sh +1 -1
  114. package/runtime/codex/bin/worktree.sh +1 -1
  115. package/runtime/codex/manifest.json +18 -1
  116. package/runtime/pi/.claude/context/notification-consent.md +66 -0
  117. package/runtime/pi/.codex/hooks/branch-guard.js +14 -3
  118. package/runtime/pi/.codex/skills/add/SKILL.md +8 -4
  119. package/runtime/pi/.codex/skills/announce/SKILL.md +21 -8
  120. package/runtime/pi/.codex/skills/answer/SKILL.md +8 -4
  121. package/runtime/pi/.codex/skills/archive/SKILL.md +8 -4
  122. package/runtime/pi/.codex/skills/ask/SKILL.md +14 -6
  123. package/runtime/pi/.codex/skills/audit/SKILL.md +29 -0
  124. package/runtime/pi/.codex/skills/autosave/SKILL.md +29 -0
  125. package/runtime/pi/.codex/skills/branch/SKILL.md +8 -4
  126. package/runtime/pi/.codex/skills/checkup/SKILL.md +8 -4
  127. package/runtime/pi/.codex/skills/commit/SKILL.md +8 -4
  128. package/runtime/pi/.codex/skills/contribute/SKILL.md +8 -4
  129. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +8 -4
  130. package/runtime/pi/.codex/skills/delete-user/SKILL.md +8 -4
  131. package/runtime/pi/.codex/skills/demo-mode/SKILL.md +29 -0
  132. package/runtime/pi/.codex/skills/deploy-bridge/SKILL.md +8 -4
  133. package/runtime/pi/.codex/skills/design/SKILL.md +29 -0
  134. package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +8 -4
  135. package/runtime/pi/.codex/skills/emissary/SKILL.md +8 -4
  136. package/runtime/pi/.codex/skills/env/SKILL.md +8 -4
  137. package/runtime/pi/.codex/skills/handoff/SKILL.md +81 -10
  138. package/runtime/pi/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
  139. package/runtime/pi/.codex/skills/harvest/SKILL.md +30 -6
  140. package/runtime/pi/.codex/skills/ingest/SKILL.md +8 -4
  141. package/runtime/pi/.codex/skills/ingest-google/SKILL.md +8 -4
  142. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +8 -4
  143. package/runtime/pi/.codex/skills/invite/SKILL.md +6 -2
  144. package/runtime/pi/.codex/skills/issue/SKILL.md +8 -4
  145. package/runtime/pi/.codex/skills/me/SKILL.md +8 -4
  146. package/runtime/pi/.codex/skills/meeting/SKILL.md +8 -4
  147. package/runtime/pi/.codex/skills/minion/SKILL.md +8 -4
  148. package/runtime/pi/.codex/skills/mock/SKILL.md +29 -0
  149. package/runtime/pi/.codex/skills/note/SKILL.md +8 -4
  150. package/runtime/pi/.codex/skills/onboarding/SKILL.md +8 -4
  151. package/runtime/pi/.codex/skills/pr/SKILL.md +8 -4
  152. package/runtime/pi/.codex/skills/product-voice/SKILL.md +29 -0
  153. package/runtime/pi/.codex/skills/project/SKILL.md +8 -4
  154. package/runtime/pi/.codex/skills/pull/SKILL.md +8 -4
  155. package/runtime/pi/.codex/skills/push/SKILL.md +8 -4
  156. package/runtime/pi/.codex/skills/quest/SKILL.md +6 -3
  157. package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +8 -4
  158. package/runtime/pi/.codex/skills/reflect/SKILL.md +8 -4
  159. package/runtime/pi/.codex/skills/review-pr/SKILL.md +8 -4
  160. package/runtime/pi/.codex/skills/save/SKILL.md +6 -4
  161. package/runtime/pi/.codex/skills/scroll/SKILL.md +92 -23
  162. package/runtime/pi/.codex/skills/scroll/assets/shell.html +381 -52
  163. package/runtime/pi/.codex/skills/session-view/SKILL.md +8 -4
  164. package/runtime/pi/.codex/skills/setup/SKILL.md +8 -4
  165. package/runtime/pi/.codex/skills/summon/SKILL.md +8 -4
  166. package/runtime/pi/.codex/skills/sync-repos/SKILL.md +8 -4
  167. package/runtime/pi/.codex/skills/task/SKILL.md +9 -5
  168. package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
  169. package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +8 -4
  170. package/runtime/pi/.codex/skills/telemetry/SKILL.md +8 -4
  171. package/runtime/pi/.codex/skills/test/SKILL.md +8 -4
  172. package/runtime/pi/.codex/skills/thread/SKILL.md +8 -4
  173. package/runtime/pi/.codex/skills/todo/SKILL.md +8 -4
  174. package/runtime/pi/.codex/skills/tui-design/SKILL.md +8 -4
  175. package/runtime/pi/.codex/skills/tutorial/SKILL.md +8 -4
  176. package/runtime/pi/.codex/skills/update/SKILL.md +8 -4
  177. package/runtime/pi/.codex/skills/visual-explain/SKILL.md +8 -4
  178. package/runtime/pi/.codex/spec-manifest.json +4 -4
  179. package/runtime/pi/.pi/APPEND_SYSTEM.md +34 -12
  180. package/runtime/pi/.pi/extensions/egregore.ts +8 -1
  181. package/runtime/pi/.pi/spec-manifest.json +2 -2
  182. package/runtime/pi/AGENTS.md +36 -14
  183. package/runtime/pi/bin/activity-data.sh +1 -1
  184. package/runtime/pi/bin/agent.sh +38 -19
  185. package/runtime/pi/bin/attendant.sh +8 -2
  186. package/runtime/pi/bin/autosave.sh +1 -1
  187. package/runtime/pi/bin/capture-reconcile.sh +8 -6
  188. package/runtime/pi/bin/capture-run.sh +1 -1
  189. package/runtime/pi/bin/codex-install-skills.sh +1 -1
  190. package/runtime/pi/bin/codex-render-spec.mjs +12 -5
  191. package/runtime/pi/bin/codex-session-start.sh +1 -1
  192. package/runtime/pi/bin/codex-skill-render.mjs +5 -0
  193. package/runtime/pi/bin/codex-sync-skills.sh +9 -5
  194. package/runtime/pi/bin/dashboard-data.sh +1 -1
  195. package/runtime/pi/bin/graph-batch.sh +1 -1
  196. package/runtime/pi/bin/graph-op.sh +1 -1
  197. package/runtime/pi/bin/graph-wal.sh +1 -1
  198. package/runtime/pi/bin/graph.sh +1 -1
  199. package/runtime/pi/bin/handoff-pr-backfill.sh +1 -1
  200. package/runtime/pi/bin/handoff-run.sh +117 -119
  201. package/runtime/pi/bin/handoff-save-egregore.sh +62 -32
  202. package/runtime/pi/bin/index-handoff.sh +3 -2
  203. package/runtime/pi/bin/ingest-graph.sh +1 -1
  204. package/runtime/pi/bin/ingest.sh +1 -1
  205. package/runtime/pi/bin/lib/artifact-id.sh +1 -1
  206. package/runtime/pi/bin/lib/config.sh +56 -20
  207. package/runtime/pi/bin/lib/context.sh +7 -1
  208. package/runtime/pi/bin/lib/ensure-develop.sh +1 -1
  209. package/runtime/pi/bin/lib/git-sync.sh +145 -59
  210. package/runtime/pi/bin/lib/greeting.sh +14 -0
  211. package/runtime/pi/bin/lib/hash.sh +1 -1
  212. package/runtime/pi/bin/lib/noncode.sh +1 -1
  213. package/runtime/pi/bin/lib/time.sh +1 -1
  214. package/runtime/pi/bin/notify.sh +492 -153
  215. package/runtime/pi/bin/person.sh +1 -1
  216. package/runtime/pi/bin/pi-product-workflows.mjs +14 -5
  217. package/runtime/pi/bin/pi-session-start.sh +1 -1
  218. package/runtime/pi/bin/publish-artifact.sh +64 -8
  219. package/runtime/pi/bin/publish-references.sh +1 -1
  220. package/runtime/pi/bin/repo-state.sh +7 -10
  221. package/runtime/pi/bin/search.sh +1 -1
  222. package/runtime/pi/bin/session-autosave.sh +1 -1
  223. package/runtime/pi/bin/session-log.sh +1 -1
  224. package/runtime/pi/bin/settings.sh +32 -2
  225. package/runtime/pi/bin/telemetry.sh +1 -1
  226. package/runtime/pi/bin/worktree-create.sh +14 -4
  227. package/runtime/pi/bin/worktree-remove.sh +1 -1
  228. package/runtime/pi/bin/worktree.sh +1 -1
  229. package/runtime/pi/manifest.json +18 -1
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
  # handoff-run.sh — atomic orchestrator for /handoff.
4
4
  #
@@ -25,7 +25,7 @@ set -euo pipefail
25
25
  # and returns a subgraph snapshot in the result JSON
26
26
  # 6. Commits + pushes memory repo (with orphan-stash dance if needed)
27
27
  # 7. Publishes HTML artifact via bin/publish-artifact.sh
28
- # 8. Sends Telegram notification via bin/notify.sh (if recipient)
28
+ # 8. Creates an exact notification proposal via bin/notify.sh (never sends)
29
29
  # 9. Emits ONE status line and ONE JSON blob on stdout
30
30
  #
31
31
  # Exit codes:
@@ -122,88 +122,63 @@ if [ ! -s "$ABS_FILE" ]; then
122
122
  exit 1
123
123
  fi
124
124
 
125
- # --- Canonical capture contract -----------------------------------------
126
- # /handoff is the addressed door into the shared capture engine. Persist the
127
- # same schema/mode fields used by /wrap and SessionEnd so filesystem and graph
128
- # retrieval can distinguish captures without inferring from directory names.
129
- if ! grep -qiE '^(capture_schema:|\*\*[Cc]apture [Ss]chema\*\*:)' "$ABS_FILE"; then
130
- CAPTURE_KIND=""
131
- if ! grep -qiE '^(kind:|\*\*[Kk]ind\*\*:)' "$ABS_FILE"; then
132
- CAPTURE_KIND="addressed"
133
- fi
134
- if [ "$(head -1 "$ABS_FILE")" = "---" ]; then
135
- awk -v kind="$CAPTURE_KIND" '
136
- NR == 1 {
137
- print
138
- print "capture_schema: egregore-capture/v1"
139
- print "capture_mode: addressed"
140
- if (kind != "") print "kind: " kind
141
- next
142
- }
143
- { print }
144
- ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
145
- else
146
- awk -v kind="$CAPTURE_KIND" '
147
- !injected && /^\*\*[Aa]uthor\*\*:/ {
148
- print
149
- print "**Capture Schema**: egregore-capture/v1"
150
- print "**Capture Mode**: addressed"
151
- if (kind != "") print "**Kind**: " kind
152
- injected=1
153
- next
154
- }
155
- { print }
156
- END {
157
- if (!injected) {
158
- print "**Capture Schema**: egregore-capture/v1"
159
- print "**Capture Mode**: addressed"
160
- if (kind != "") print "**Kind**: " kind
161
- }
162
- }
163
- ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
164
- fi
165
- fi
125
+ # --- Canonical metadata boundary ----------------------------------------
126
+ # Callers are allowed to send prose-only markdown, but persisted handoffs are
127
+ # not. Normalize every input to the same frontmatter contract before indexing
128
+ # or rendering so title/author/recipient cannot disappear at the adapter seam.
129
+ HAS_FRONTMATTER=0
130
+ [ "$(head -1 "$ABS_FILE")" = "---" ] && HAS_FRONTMATTER=1
166
131
 
167
- # --- Inject **To**: line if --recipient given and body omits it -----
168
- # index-handoff.sh parses recipients from the file body. Skills
169
- # normally write the To line themselves, but callers that invoke
170
- # handoff-run.sh directly often skip it. Inject after the Author
171
- # line so the graph gets the HANDED_TO edge.
172
- if [ -n "$RECIPIENT" ] && ! grep -qi "^\*\*[Tt]o\*\*:" "$ABS_FILE"; then
173
- awk -v r="$RECIPIENT" '
174
- !injected && /^\*\*[Aa]uthor\*\*:/ {
175
- print
176
- print "**To**: " r
177
- injected=1
178
- next
179
- }
180
- { print }
181
- ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
182
- fi
132
+ _has_frontmatter_key() {
133
+ [ "$HAS_FRONTMATTER" = "1" ] && sed -n '2,/^---$/p' "$ABS_FILE" | grep -qiE "^${1}:"
134
+ }
183
135
 
184
- # --- Persist lifecycle intent in the canonical handoff file -------------
185
- if ! grep -qiE '^(intent:|\*\*[Ii]ntent\*\*:)' "$ABS_FILE"; then
186
- if [ "$(head -1 "$ABS_FILE")" = "---" ]; then
187
- awk -v intent="$INTENT" '
188
- NR == 1 { print; print "intent: " intent; next }
189
- { print }
190
- ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
191
- else
192
- awk -v intent="$INTENT" '
193
- !injected && /^\*\*[Aa]uthor\*\*:/ {
194
- print
195
- print "**Intent**: " intent
196
- injected=1
197
- next
198
- }
199
- { print }
200
- END {
201
- if (!injected) print "**Intent**: " intent
202
- }
203
- ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
204
- fi
136
+ MISSING_SCHEMA=0; _has_frontmatter_key capture_schema || MISSING_SCHEMA=1
137
+ MISSING_MODE=0; _has_frontmatter_key capture_mode || MISSING_MODE=1
138
+ MISSING_KIND=0; _has_frontmatter_key kind || MISSING_KIND=1
139
+ MISSING_FROM=0; _has_frontmatter_key from || _has_frontmatter_key author || MISSING_FROM=1
140
+ MISSING_DATE=0; _has_frontmatter_key date || MISSING_DATE=1
141
+ MISSING_TOPIC=0; _has_frontmatter_key topic || MISSING_TOPIC=1
142
+ MISSING_INTENT=0; _has_frontmatter_key intent || MISSING_INTENT=1
143
+ MISSING_RECIPIENT=0
144
+ if [ -n "$RECIPIENT" ]; then
145
+ _has_frontmatter_key addressed_to || _has_frontmatter_key to || MISSING_RECIPIENT=1
205
146
  fi
206
147
 
148
+ awk \
149
+ -v has_frontmatter="$HAS_FRONTMATTER" \
150
+ -v schema="$MISSING_SCHEMA" -v mode="$MISSING_MODE" -v kind="$MISSING_KIND" \
151
+ -v from="$MISSING_FROM" -v date_missing="$MISSING_DATE" \
152
+ -v topic_missing="$MISSING_TOPIC" -v intent_missing="$MISSING_INTENT" \
153
+ -v recipient_missing="$MISSING_RECIPIENT" \
154
+ -v author="$AUTHOR" -v date="$TODAY" -v topic="$TOPIC" \
155
+ -v intent="$INTENT" -v recipient="$RECIPIENT" '
156
+ function metadata() {
157
+ if (schema) print "capture_schema: egregore-capture/v1"
158
+ if (mode) print "capture_mode: addressed"
159
+ if (kind) print "kind: addressed"
160
+ if (from) print "from: " author
161
+ if (recipient_missing) print "addressed_to: " recipient
162
+ if (date_missing) print "date: " date
163
+ if (topic_missing) print "topic: " topic
164
+ if (intent_missing) print "intent: " intent
165
+ }
166
+ BEGIN {
167
+ if (!has_frontmatter) {
168
+ print "---"
169
+ metadata()
170
+ print "---"
171
+ print ""
172
+ }
173
+ }
174
+ has_frontmatter && NR == 1 {
175
+ print
176
+ metadata()
177
+ next
178
+ }
179
+ { print }
180
+ ' "$ABS_FILE" > "$ABS_FILE.new" && mv "$ABS_FILE.new" "$ABS_FILE"
181
+
207
182
  # --- Append repo state ---------------------------------------------------
208
183
  # --no-pr skips `gh pr list` (~400–600ms per repo). A detached PR backfill
209
184
  # after the parallel phase rewrites `—` → `#N` and re-pushes memory.
@@ -231,14 +206,14 @@ awk -v line="$IDX_LINE" '
231
206
  END { if (!inserted) print line }
232
207
  ' "$INDEX" > "$INDEX.new" && mv "$INDEX.new" "$INDEX"
233
208
 
234
- # --- Parallel stage: graph + memory + (publish → notify) ----------------
209
+ # --- Parallel stage: graph + memory + (publish → notification proposal) -
235
210
  #
236
211
  # Three independent branches fork here and join before we emit the result:
237
212
  # A. Graph index — reads ABS_FILE, writes Session node to Neo4j, and
238
213
  # returns the handoff's neighborhood as subgraph JSON.
239
214
  # B. Memory push — commits + pushes memory repo (orphan-stash dance).
240
- # C. Publish+notify — publishes HTML artifact, then (if recipient is set)
241
- # sends Telegram with the artifact URL embedded.
215
+ # C. Publish+plan — publishes HTML artifact, then creates an immutable
216
+ # notification proposal with the artifact URL embedded.
242
217
  #
243
218
  # Each branch writes its result to a tmpfile. Wall-clock is max(A,B,C).
244
219
  #
@@ -251,7 +226,7 @@ MEMORY_DIR="$SCRIPT_DIR/memory"
251
226
  TMPD=$(mktemp -d -t handoff-run-XXXXXX)
252
227
  trap 'rm -rf "$TMPD"' EXIT
253
228
 
254
- # Extract briefing text once (used by publish and notify) so we don't
229
+ # Extract briefing text once (used by publish and the proposal) so we don't
255
230
  # re-awk the same file inside multiple workers.
256
231
  BRIEFING_LEAD=$(awk '/^## Briefing/{found=1; next} found && /^##/{exit} found && NF{print}' "$ABS_FILE" 2>/dev/null \
257
232
  | head -2 | tr '\n' ' ' | cut -c1-200 || true)
@@ -390,19 +365,27 @@ PID_MEMORY=$!
390
365
  fi
391
366
  EMISSARY_API_URL="${EMISSARY_API_URL:-https://egregore-production-55f2.up.railway.app/api/v1/emissary}"
392
367
 
393
- if [ -n "$EMISSARY_TOKEN" ]; then
368
+ # /handoff is an internal team primitive, not an implicit public-emissary
369
+ # composer. Use the emissary route only for an explicit recipient, and make
370
+ # that artifact directed-private. Recipient-less handoffs fall through to
371
+ # the org-scoped publisher (connected) or opt-in relay (local).
372
+ if [ -n "$EMISSARY_TOKEN" ] && [ -n "$RECIPIENT" ]; then
394
373
  # Step 1: render the handoff to HTML locally using egregore-artifacts.
395
374
  # Same renderer + template publish-artifact.sh uses today — handoffs
396
375
  # keep their familiar look.
397
376
  RENDERED_HTML="$TMPD/handoff.html"
398
377
  RENDER_OK=0
399
378
  LOCAL_CLI="$SCRIPT_DIR/packages/egregore-artifacts/bin/cli.js"
379
+ FIDELITY_ARGS=(--verify-fidelity)
380
+ if [ "$RENDER_TYPE" = "composed" ]; then
381
+ FIDELITY_ARGS+=(--source "$ABS_FILE")
382
+ fi
400
383
  if [ "${EGREGORE_USE_PUBLISHED:-0}" != "1" ] && [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
401
- if node "$LOCAL_CLI" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" --output "$RENDERED_HTML" >/dev/null 2>&1; then
384
+ if node "$LOCAL_CLI" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" "${FIDELITY_ARGS[@]}" --output "$RENDERED_HTML" >/dev/null 2>"$TMPD/render-error"; then
402
385
  RENDER_OK=1
403
386
  fi
404
387
  else
405
- if npx egregore-artifacts "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" --output "$RENDERED_HTML" >/dev/null 2>&1; then
388
+ if npx -y egregore-artifacts@latest "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" "${FIDELITY_ARGS[@]}" --output "$RENDERED_HTML" >/dev/null 2>"$TMPD/render-error"; then
406
389
  RENDER_OK=1
407
390
  fi
408
391
  fi
@@ -422,12 +405,8 @@ PID_MEMORY=$!
422
405
  DISPLAY_NAME=$(head -1 "$PERSON_FILE" | sed 's/^# //')
423
406
  fi
424
407
 
425
- # addressed_to: only set if there's a recipient
426
- ADDRESSED_TO="[]"
427
- if [ -n "$RECIPIENT" ]; then
428
- RECIP_HANDLE=$(echo "$RECIPIENT" | tr '[:upper:]' '[:lower:]' | awk '{print $1}')
429
- ADDRESSED_TO=$(jq -nc --arg h "$RECIP_HANDLE" --arg d "$RECIPIENT" '[{"handle":$h,"display":$d}]')
430
- fi
408
+ RECIP_HANDLE=$(echo "$RECIPIENT" | tr '[:upper:]' '[:lower:]' | awk '{print $1}')
409
+ ADDRESSED_TO=$(jq -nc --arg h "$RECIP_HANDLE" --arg d "$RECIPIENT" '[{"handle":$h,"display":$d}]')
431
410
 
432
411
  CLAIM=$(echo "$BRIEFING_LEAD" | cut -c1-200)
433
412
 
@@ -456,8 +435,8 @@ PID_MEMORY=$!
456
435
  body: { prose: $prose },
457
436
  audience: {
458
437
  addressed_to: $addressed,
459
- visible_to: "public",
460
- extendable_by: "anyone"
438
+ visible_to: $addressed,
439
+ extendable_by: $addressed
461
440
  },
462
441
  parents: [],
463
442
  render_mode: "custom",
@@ -475,16 +454,35 @@ PID_MEMORY=$!
475
454
  fi
476
455
  fi
477
456
 
478
- # Fallback: if the emissary publish didn't produce a URL (no token, no
479
- # network, size cap, render failure), fire the legacy publish-artifact.sh
480
- # so handoffs still get a Telegram-able URL.
457
+ # Fallback: if a directed emissary publish didn't produce a URL—or this is a
458
+ # recipient-less team handoff—use publish-artifact.sh. Connected mode is
459
+ # authenticated and org-scoped; local mode's public relay is opt-in.
460
+ PUBLISH_RC=0
481
461
  if [ -z "$V1URL" ] && [ "$NO_PUBLISH" = "0" ] && [ -x "$SCRIPT_DIR/bin/publish-artifact.sh" ]; then
482
462
  AURL=$(bash "$SCRIPT_DIR/bin/publish-artifact.sh" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" \
463
+ --verify-fidelity \
464
+ --source "$ABS_FILE" \
483
465
  --title "$TOPIC" \
484
466
  --author "$AUTHOR" \
485
- --description "$BRIEFING_LEAD" 2>/dev/null || echo "")
467
+ --description "$BRIEFING_LEAD" 2>"$TMPD/publish-error") || PUBLISH_RC=$?
486
468
  fi
487
469
 
470
+ PS="published"
471
+ if [ "$NO_PUBLISH" = "1" ]; then
472
+ PS="disabled"
473
+ elif [ -n "$V1URL" ] || [ -n "$AURL" ]; then
474
+ PS="published"
475
+ elif [ "$PUBLISH_RC" = "4" ]; then
476
+ PS="relay-off"
477
+ elif [ "$PUBLISH_RC" = "3" ]; then
478
+ PS="hosting-off"
479
+ elif grep -q 'Handoff fidelity check failed' "$TMPD/render-error" "$TMPD/publish-error" 2>/dev/null; then
480
+ PS="fidelity-failed"
481
+ else
482
+ PS="failed"
483
+ fi
484
+ echo "$PS" > "$TMPD/publish"
485
+
488
486
  # Prefer v1 (emissary-rendered) URL when available; fall back to the
489
487
  # legacy egregore-artifacts URL only if the v1 publish failed.
490
488
  NOTIFY_URL=""
@@ -497,6 +495,7 @@ PID_MEMORY=$!
497
495
  fi
498
496
 
499
497
  NS="skipped"
498
+ echo '{}' > "$TMPD/notify-plan"
500
499
  if [ "$NO_NOTIFY" = "0" ]; then
501
500
  if [ -n "$NOTIFY_URL" ]; then
502
501
  MSG_NOTIFY="Handoff from ${AUTHOR}: ${TOPIC}
@@ -510,21 +509,19 @@ View: ${NOTIFY_URL}"
510
509
  \"${BRIEFING_SHORT}\""
511
510
  fi
512
511
 
513
- # Always notify. With a recipient (connected mode) → DM. Otherwise → group.
514
- # Self-handoffs still post to the group so they're visible on /activity
515
- # and in the Telegram feed — a handoff without a Telegram beat is invisible.
516
- if [ -n "$RECIPIENT" ] && [ "$MODE" = "connected" ]; then
517
- NR=$(bash "$SCRIPT_DIR/bin/notify.sh" send "$RECIPIENT" "$MSG_NOTIFY" 2>/dev/null || echo "Failed")
512
+ # Resolve the exact destination, but never approve or dispatch here. The
513
+ # interactive harness must show this proposal in a separate checkpoint.
514
+ if [ -n "$RECIPIENT" ]; then
515
+ NR=$(bash "$SCRIPT_DIR/bin/notify.sh" plan send "$RECIPIENT" "$MSG_NOTIFY" 2>/dev/null || echo '{}')
518
516
  else
519
- NR=$(bash "$SCRIPT_DIR/bin/notify.sh" group "$MSG_NOTIFY" 2>/dev/null || echo "Failed")
517
+ NR=$(bash "$SCRIPT_DIR/bin/notify.sh" plan group "$MSG_NOTIFY" 2>/dev/null || echo '{}')
520
518
  fi
521
519
 
522
- if echo "$NR" | grep -qi "^Sent"; then
523
- NS="sent"
524
- elif echo "$NR" | grep -qi "^Failed"; then
525
- NS="failed"
520
+ if printf '%s' "$NR" | jq -e '.status == "approval_required"' >/dev/null 2>&1; then
521
+ NS="approval_required"
522
+ printf '%s\n' "$NR" > "$TMPD/notify-plan"
526
523
  else
527
- NS="unknown"
524
+ NS="unavailable"
528
525
  fi
529
526
  fi
530
527
  echo "$NS" > "$TMPD/notify"
@@ -574,6 +571,9 @@ fi
574
571
  MEMORY_STATUS=$(cat "$TMPD/memory" 2>/dev/null || echo "skipped")
575
572
  ARTIFACT_URL=$(cat "$TMPD/artifact" 2>/dev/null || echo "")
576
573
  NOTIFY_STATUS=$(cat "$TMPD/notify" 2>/dev/null || echo "skipped")
574
+ NOTIFY_PLAN=$(cat "$TMPD/notify-plan" 2>/dev/null || echo "{}")
575
+ PUBLISH_STATUS=$(cat "$TMPD/publish" 2>/dev/null || echo "skipped")
576
+ [ -z "$PUBLISH_STATUS" ] && PUBLISH_STATUS="skipped"
577
577
  ARTIFACTS_ARR=$(cat "$TMPD/artifacts" 2>/dev/null || echo "[]")
578
578
  [ -z "$ARTIFACTS_ARR" ] && ARTIFACTS_ARR="[]"
579
579
 
@@ -594,16 +594,10 @@ fi
594
594
  STATUS_BITS=("saved")
595
595
  [ "$GRAPH_STATUS" = "ok" ] && STATUS_BITS+=("graphed")
596
596
  [ "$MEMORY_STATUS" = "ok" ] && STATUS_BITS+=("pushed")
597
- if [ "$NOTIFY_STATUS" = "sent" ]; then
598
- if [ -n "$RECIPIENT" ]; then
599
- STATUS_BITS+=("${RECIPIENT} notified")
600
- else
601
- STATUS_BITS+=("group notified")
602
- fi
603
- elif [ "$NOTIFY_STATUS" = "unknown" ] && [ -n "$RECIPIENT" ]; then
604
- STATUS_BITS+=("${RECIPIENT} relayed to group")
605
- fi
597
+ [ "$NOTIFY_STATUS" = "approval_required" ] && STATUS_BITS+=("notify approval pending")
606
598
  [ -n "$ARTIFACT_URL" ] && STATUS_BITS+=("published")
599
+ [ "$PUBLISH_STATUS" = "relay-off" ] && STATUS_BITS+=("not published")
600
+ [ "$PUBLISH_STATUS" = "fidelity-failed" ] && STATUS_BITS+=("artifact fidelity failed")
607
601
 
608
602
  STATUS_LINE=""
609
603
  for bit in "${STATUS_BITS[@]}"; do
@@ -625,7 +619,9 @@ jq -cn \
625
619
  --arg graphStatus "$GRAPH_STATUS" \
626
620
  --arg memoryStatus "$MEMORY_STATUS" \
627
621
  --arg notifyStatus "$NOTIFY_STATUS" \
622
+ --argjson notifyPlan "$NOTIFY_PLAN" \
628
623
  --arg artifactUrl "$ARTIFACT_URL" \
624
+ --arg publishStatus "$PUBLISH_STATUS" \
629
625
  --arg recipient "$RECIPIENT" \
630
626
  --arg topic "$TOPIC" \
631
627
  --arg author "$AUTHOR" \
@@ -640,7 +636,9 @@ jq -cn \
640
636
  graphStatus:$graphStatus,
641
637
  memoryStatus:$memoryStatus,
642
638
  notifyStatus:$notifyStatus,
639
+ notifyPlan:$notifyPlan,
643
640
  artifactUrl:$artifactUrl,
641
+ publishStatus:$publishStatus,
644
642
  recipient:$recipient,
645
643
  topic:$topic,
646
644
  author:$author,
@@ -1,13 +1,14 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # handoff-save-egregore.sh — background save+auto-merge for the core repo after a handoff.
3
3
  #
4
4
  # /handoff renders its card first, then fires this detached. The user never waits on git.
5
5
  #
6
6
  # Behavior:
7
7
  # - If nothing to save (clean working tree + up-to-date with origin) → exit silently.
8
- # - If on develop/main/master → create dev/{author}/handoff-{YYYY-MM-DD} branch from origin/develop.
9
- # - Commit all changes, rebase onto origin/develop, push.
10
- # - If push succeeds: create PR to develop (or reuse existing), then:
8
+ # - If on the configured base (or another protected branch) → create a
9
+ # dev/{author}/handoff-{YYYY-MM-DD} branch from origin/{base}.
10
+ # - Commit all changes, rebase onto origin/{base}, push.
11
+ # - If push succeeds: create a PR to the configured base (or reuse existing), then:
11
12
  # - Markdown-only diff → `gh pr merge --auto --merge` (auto-merges when checks pass).
12
13
  # - Code/config present → leave PR open for review (no auto-merge).
13
14
  #
@@ -45,9 +46,19 @@ while [ $# -gt 0 ]; do
45
46
  done
46
47
 
47
48
  case "$KIND" in
48
- autosave) MSG_PREFIX="Auto-save" ; PR_BODY="Auto-saved session content (non-coding). No explicit /save needed." ;;
49
- *) MSG_PREFIX="Handoff" ; PR_BODY="Auto-created by /handoff. Session work for:" ;;
49
+ autosave)
50
+ MSG_PREFIX="Auto-save"
51
+ PR_WHAT="Save session content captured by the opted-in autosave workflow."
52
+ PR_WHY="This preserves unattended non-coding work without requiring an explicit /save."
53
+ ;;
54
+ *)
55
+ MSG_PREFIX="Handoff"
56
+ PR_WHAT="Save core-repository session work captured when the handoff was created."
57
+ PR_WHY="The handoff records shared context immediately; this companion PR keeps the originating checkout's work from remaining only local."
58
+ ;;
50
59
  esac
60
+ PR_BODY=$(printf '## What\n\n- %s\n\n## Why\n\n%s Topic: `%s`.\n\n## Verification\n\nNot verified — background %s save; review code or configuration changes before merging.\n\n🤖 Saved via `bin/handoff-save-egregore.sh`\n' \
61
+ "$PR_WHAT" "$PR_WHY" "$TOPIC" "$KIND")
51
62
 
52
63
  [ -n "$AUTHOR" ] || { echo "handoff-save-egregore: missing author" >&2; exit 1; }
53
64
 
@@ -56,6 +67,22 @@ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
56
67
  [ -z "$REPO_DIR" ] && REPO_DIR="$SCRIPT_DIR"
57
68
  cd "$REPO_DIR" || exit 1
58
69
 
70
+ # Resolve the target checkout's configured integration branch. SCRIPT_DIR points
71
+ # at the framework that owns this helper, while CONFIG must follow --repo-dir so
72
+ # sandboxed and installed instances read their own egregore.json.
73
+ CONFIG="$REPO_DIR/egregore.json"
74
+ [ -f "$SCRIPT_DIR/bin/lib/config.sh" ] || {
75
+ echo "handoff-save-egregore: base-branch resolver is unavailable" >&2
76
+ exit 1
77
+ }
78
+ # shellcheck source=bin/lib/config.sh
79
+ . "$SCRIPT_DIR/bin/lib/config.sh" 2>/dev/null || exit 1
80
+ if ! BASE_BRANCH=$(_get_base_branch); then
81
+ echo "handoff-save-egregore: could not resolve the configured base branch" >&2
82
+ exit 1
83
+ fi
84
+ BASE_REF="origin/$BASE_BRANCH"
85
+
59
86
  # Shared safe-staging guard — never auto-commit stray sibling-repo gitlinks.
60
87
  # shellcheck source=bin/lib/git-safe.sh
61
88
  . "$SCRIPT_DIR/bin/lib/git-safe.sh" 2>/dev/null || true
@@ -65,7 +92,7 @@ type git_add_guarded >/dev/null 2>&1 || git_add_guarded() { git add -A 2>/dev/nu
65
92
  # shellcheck source=bin/lib/noncode.sh
66
93
  . "$SCRIPT_DIR/bin/lib/noncode.sh" 2>/dev/null || true
67
94
  type noncode_blockers >/dev/null 2>&1 || noncode_blockers() {
68
- git -C "${2:-.}" diff "${1:-origin/develop}...HEAD" --name-only 2>/dev/null | grep -v '\.md$' | head -1 || true
95
+ git -C "${2:-.}" diff "${1:-$BASE_REF}...HEAD" --name-only 2>/dev/null | grep -v '\.md$' | head -1 || true
69
96
  }
70
97
 
71
98
  # --- Early exit if nothing to do -----------------------------------------
@@ -75,9 +102,12 @@ DIRTY=0
75
102
  CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")
76
103
  AHEAD=0
77
104
  if [ -n "$CURRENT_BRANCH" ]; then
78
- # Count commits ahead of origin/develop on the current branch (works from any
79
- # dev/* branch or from develop itself).
80
- AHEAD=$(git rev-list --count "origin/develop..HEAD" 2>/dev/null || echo 0)
105
+ # A missing remote base is not evidence that there is nothing to save. The
106
+ # former `|| echo 0` made a main-only instance silently discard clean,
107
+ # committed topic work because origin/develop did not exist.
108
+ if ! AHEAD=$(git rev-list --count "$BASE_REF..HEAD" 2>/dev/null); then
109
+ AHEAD=1
110
+ fi
81
111
  fi
82
112
 
83
113
  if [ "$DIRTY" = "0" ] && [ "$AHEAD" = "0" ]; then
@@ -85,18 +115,18 @@ if [ "$DIRTY" = "0" ] && [ "$AHEAD" = "0" ]; then
85
115
  fi
86
116
 
87
117
  # --- Protect the protected branches: create a working branch if needed --
88
- case "$CURRENT_BRANCH" in
89
- develop|main|master|"")
90
- SLUG_DATE=$(date +%Y-%m-%d)
91
- # --branch-suffix keeps concurrent rescues distinct (e.g. per-checkout
92
- # hash from the autosave sweep) — same-name pushes wedge on non-FF.
93
- NEW_BRANCH="dev/${AUTHOR}/${KIND}-${SLUG_DATE}${BRANCH_SUFFIX:+-$BRANCH_SUFFIX}"
94
- git fetch origin develop --quiet 2>/dev/null || true
95
- git checkout -b "$NEW_BRANCH" origin/develop --quiet 2>/dev/null || \
96
- git checkout "$NEW_BRANCH" --quiet 2>/dev/null || exit 0
97
- CURRENT_BRANCH="$NEW_BRANCH"
98
- ;;
99
- esac
118
+ if [ -z "$CURRENT_BRANCH" ] || [ "$CURRENT_BRANCH" = "$BASE_BRANCH" ] \
119
+ || [ "$CURRENT_BRANCH" = "develop" ] || [ "$CURRENT_BRANCH" = "main" ] \
120
+ || [ "$CURRENT_BRANCH" = "master" ]; then
121
+ SLUG_DATE=$(date +%Y-%m-%d)
122
+ # --branch-suffix keeps concurrent rescues distinct (e.g. per-checkout
123
+ # hash from the autosave sweep) — same-name pushes wedge on non-FF.
124
+ NEW_BRANCH="dev/${AUTHOR}/${KIND}-${SLUG_DATE}${BRANCH_SUFFIX:+-$BRANCH_SUFFIX}"
125
+ git fetch origin "$BASE_BRANCH" --quiet 2>/dev/null || true
126
+ git checkout -b "$NEW_BRANCH" "$BASE_REF" --quiet 2>/dev/null || \
127
+ git checkout "$NEW_BRANCH" --quiet 2>/dev/null || exit 0
128
+ CURRENT_BRANCH="$NEW_BRANCH"
129
+ fi
100
130
 
101
131
  # --- Commit whatever is uncommitted --------------------------------------
102
132
  if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
@@ -104,11 +134,11 @@ if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
104
134
  git commit -m "${MSG_PREFIX}: ${TOPIC}" --quiet 2>/dev/null || true
105
135
  fi
106
136
 
107
- # --- Rebase onto develop, fall back to merge if rebase conflicts ---------
108
- git fetch origin develop --quiet 2>/dev/null || true
109
- if ! git rebase origin/develop --quiet 2>/dev/null; then
137
+ # --- Rebase onto the configured base, fall back to merge on conflicts ----
138
+ git fetch origin "$BASE_BRANCH" --quiet 2>/dev/null || true
139
+ if ! git rebase "$BASE_REF" --quiet 2>/dev/null; then
110
140
  git rebase --abort 2>/dev/null || true
111
- if ! git merge origin/develop --quiet -m "Sync with develop" 2>/dev/null; then
141
+ if ! git merge "$BASE_REF" --quiet -m "Sync with $BASE_BRANCH" 2>/dev/null; then
112
142
  # Conflicts we can't auto-resolve. Leave the branch as-is; the user will see it
113
143
  # next session or when they run /save explicitly.
114
144
  git merge --abort 2>/dev/null || true
@@ -128,7 +158,7 @@ fi
128
158
  LEDGER="${EGREGORE_AUTOSAVE_LOG:-$HOME/.egregore/autosave.log}"
129
159
  ledger_write() { # pr outcome
130
160
  local n_files
131
- n_files=$(git diff origin/develop...HEAD --name-only 2>/dev/null | grep -c . || echo 0)
161
+ n_files=$(git diff "$BASE_REF...HEAD" --name-only 2>/dev/null | grep -c . || echo 0)
132
162
  mkdir -p "$(dirname "$LEDGER")" 2>/dev/null || true
133
163
  printf '%s|%s|%s|%s|%s|%s|%s\n' \
134
164
  "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$KIND" "$REPO_DIR" "$CURRENT_BRANCH" \
@@ -145,15 +175,15 @@ EXISTING_BASE=$(echo "$EXISTING" | jq -r '.baseRefName // empty' 2>/dev/null)
145
175
 
146
176
  if [ -n "$EXISTING_NUMBER" ]; then
147
177
  PR_NUMBER="$EXISTING_NUMBER"
148
- if [ "$EXISTING_BASE" != "develop" ]; then
149
- gh pr edit "$PR_NUMBER" --base develop >/dev/null 2>&1 || true
178
+ if [ "$EXISTING_BASE" != "$BASE_BRANCH" ]; then
179
+ gh pr edit "$PR_NUMBER" --base "$BASE_BRANCH" >/dev/null 2>&1 || true
150
180
  fi
151
181
  else
152
182
  PR_URL=$(gh pr create \
153
- --base develop \
183
+ --base "$BASE_BRANCH" \
154
184
  --head "$CURRENT_BRANCH" \
155
185
  --title "${MSG_PREFIX}: ${TOPIC}" \
156
- --body "${PR_BODY} ${TOPIC}" \
186
+ --body "$PR_BODY" \
157
187
  2>/dev/null || echo "")
158
188
  PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$' || echo "")
159
189
  fi
@@ -167,7 +197,7 @@ fi
167
197
  # pending; on a repo with no branch protection it always errors. Fall back to
168
198
  # an immediate merge so non-coding PRs never sit open.
169
199
  OUTCOME="open"
170
- NON_CODE_BLOCKER=$(noncode_blockers origin/develop .)
200
+ NON_CODE_BLOCKER=$(noncode_blockers "$BASE_REF" .)
171
201
  if [ -z "$NON_CODE_BLOCKER" ]; then
172
202
  if [ "$PUBLISH" = "gate" ]; then
173
203
  OUTCOME="staged"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  # Index a single handoff file into the Neo4j graph.
@@ -119,11 +119,12 @@ AUTHOR="$(md_field 'Author')"
119
119
  AUTHOR_HANDLE="$(echo "$AUTHOR" | sed 's/[[:space:]]*→.*//' | awk '{print tolower($1)}')"
120
120
  [ -z "$AUTHOR_HANDLE" ] && AUTHOR_HANDLE="unknown"
121
121
 
122
- # Recipients: try markdown header (To or For), then YAML (to or for)
122
+ # Recipients: try markdown header, then canonical/legacy YAML names.
123
123
  RECIPIENTS_RAW="$(md_field 'To')"
124
124
  [ -z "$RECIPIENTS_RAW" ] && RECIPIENTS_RAW="$(md_field 'For')"
125
125
  [ -z "$RECIPIENTS_RAW" ] && RECIPIENTS_RAW="$(yaml_extract 'to')"
126
126
  [ -z "$RECIPIENTS_RAW" ] && RECIPIENTS_RAW="$(yaml_extract 'for')"
127
+ [ -z "$RECIPIENTS_RAW" ] && RECIPIENTS_RAW="$(yaml_extract 'addressed_to')"
127
128
  # Also extract from "From: author → recipient" pattern
128
129
  if [ -z "$RECIPIENTS_RAW" ] && echo "$AUTHOR" | grep -q '→' 2>/dev/null; then
129
130
  RECIPIENTS_RAW="$(echo "$AUTHOR" | sed 's/.*→[[:space:]]*//')"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  # Validate, plan, or apply a durable ingestion manifest to the organization graph.
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  # Org-scoped intake plane. Shared manifests live in memory/; normalized bodies
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # artifact-id.sh — Deterministic artifact IDs for memory files.
3
3
  #
4
4
  # Emits `{prefix}-{12 hex}` where prefix is derived from the file extension