create-egregore 0.19.20 → 0.19.22

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 (226) hide show
  1. package/assets/egregore-launcher.js +124 -12
  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 +15 -6
  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-sync-skills.sh +9 -5
  81. package/runtime/codex/bin/dashboard-data.sh +1 -1
  82. package/runtime/codex/bin/graph-batch.sh +1 -1
  83. package/runtime/codex/bin/graph-op.sh +1 -1
  84. package/runtime/codex/bin/graph-wal.sh +1 -1
  85. package/runtime/codex/bin/graph.sh +1 -1
  86. package/runtime/codex/bin/handoff-pr-backfill.sh +1 -1
  87. package/runtime/codex/bin/handoff-run.sh +53 -39
  88. package/runtime/codex/bin/handoff-save-egregore.sh +62 -32
  89. package/runtime/codex/bin/index-handoff.sh +1 -1
  90. package/runtime/codex/bin/ingest-graph.sh +1 -1
  91. package/runtime/codex/bin/ingest.sh +1 -1
  92. package/runtime/codex/bin/lib/artifact-id.sh +1 -1
  93. package/runtime/codex/bin/lib/config.sh +56 -20
  94. package/runtime/codex/bin/lib/context.sh +7 -1
  95. package/runtime/codex/bin/lib/ensure-develop.sh +1 -1
  96. package/runtime/codex/bin/lib/git-sync.sh +145 -59
  97. package/runtime/codex/bin/lib/greeting.sh +14 -0
  98. package/runtime/codex/bin/lib/hash.sh +1 -1
  99. package/runtime/codex/bin/lib/noncode.sh +1 -1
  100. package/runtime/codex/bin/lib/time.sh +1 -1
  101. package/runtime/codex/bin/notify.sh +492 -153
  102. package/runtime/codex/bin/person.sh +1 -1
  103. package/runtime/codex/bin/publish-artifact.sh +39 -4
  104. package/runtime/codex/bin/publish-references.sh +1 -1
  105. package/runtime/codex/bin/repo-state.sh +7 -10
  106. package/runtime/codex/bin/search.sh +1 -1
  107. package/runtime/codex/bin/session-autosave.sh +1 -1
  108. package/runtime/codex/bin/session-log.sh +1 -1
  109. package/runtime/codex/bin/settings.sh +32 -2
  110. package/runtime/codex/bin/telemetry.sh +1 -1
  111. package/runtime/codex/bin/worktree-create.sh +14 -4
  112. package/runtime/codex/bin/worktree-remove.sh +1 -1
  113. package/runtime/codex/bin/worktree.sh +1 -1
  114. package/runtime/codex/manifest.json +18 -1
  115. package/runtime/pi/.claude/context/notification-consent.md +66 -0
  116. package/runtime/pi/.codex/hooks/branch-guard.js +14 -3
  117. package/runtime/pi/.codex/skills/add/SKILL.md +8 -4
  118. package/runtime/pi/.codex/skills/announce/SKILL.md +21 -8
  119. package/runtime/pi/.codex/skills/answer/SKILL.md +8 -4
  120. package/runtime/pi/.codex/skills/archive/SKILL.md +8 -4
  121. package/runtime/pi/.codex/skills/ask/SKILL.md +14 -6
  122. package/runtime/pi/.codex/skills/audit/SKILL.md +29 -0
  123. package/runtime/pi/.codex/skills/autosave/SKILL.md +29 -0
  124. package/runtime/pi/.codex/skills/branch/SKILL.md +8 -4
  125. package/runtime/pi/.codex/skills/checkup/SKILL.md +8 -4
  126. package/runtime/pi/.codex/skills/commit/SKILL.md +8 -4
  127. package/runtime/pi/.codex/skills/contribute/SKILL.md +8 -4
  128. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +8 -4
  129. package/runtime/pi/.codex/skills/delete-user/SKILL.md +8 -4
  130. package/runtime/pi/.codex/skills/demo-mode/SKILL.md +29 -0
  131. package/runtime/pi/.codex/skills/deploy-bridge/SKILL.md +8 -4
  132. package/runtime/pi/.codex/skills/design/SKILL.md +29 -0
  133. package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +8 -4
  134. package/runtime/pi/.codex/skills/emissary/SKILL.md +8 -4
  135. package/runtime/pi/.codex/skills/env/SKILL.md +8 -4
  136. package/runtime/pi/.codex/skills/handoff/SKILL.md +15 -6
  137. package/runtime/pi/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
  138. package/runtime/pi/.codex/skills/harvest/SKILL.md +30 -6
  139. package/runtime/pi/.codex/skills/ingest/SKILL.md +8 -4
  140. package/runtime/pi/.codex/skills/ingest-google/SKILL.md +8 -4
  141. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +8 -4
  142. package/runtime/pi/.codex/skills/invite/SKILL.md +6 -2
  143. package/runtime/pi/.codex/skills/issue/SKILL.md +8 -4
  144. package/runtime/pi/.codex/skills/me/SKILL.md +8 -4
  145. package/runtime/pi/.codex/skills/meeting/SKILL.md +8 -4
  146. package/runtime/pi/.codex/skills/minion/SKILL.md +8 -4
  147. package/runtime/pi/.codex/skills/mock/SKILL.md +29 -0
  148. package/runtime/pi/.codex/skills/note/SKILL.md +8 -4
  149. package/runtime/pi/.codex/skills/onboarding/SKILL.md +8 -4
  150. package/runtime/pi/.codex/skills/pr/SKILL.md +8 -4
  151. package/runtime/pi/.codex/skills/product-voice/SKILL.md +29 -0
  152. package/runtime/pi/.codex/skills/project/SKILL.md +8 -4
  153. package/runtime/pi/.codex/skills/pull/SKILL.md +8 -4
  154. package/runtime/pi/.codex/skills/push/SKILL.md +8 -4
  155. package/runtime/pi/.codex/skills/quest/SKILL.md +6 -3
  156. package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +8 -4
  157. package/runtime/pi/.codex/skills/reflect/SKILL.md +8 -4
  158. package/runtime/pi/.codex/skills/review-pr/SKILL.md +8 -4
  159. package/runtime/pi/.codex/skills/save/SKILL.md +6 -4
  160. package/runtime/pi/.codex/skills/scroll/SKILL.md +92 -23
  161. package/runtime/pi/.codex/skills/scroll/assets/shell.html +381 -52
  162. package/runtime/pi/.codex/skills/session-view/SKILL.md +8 -4
  163. package/runtime/pi/.codex/skills/setup/SKILL.md +8 -4
  164. package/runtime/pi/.codex/skills/summon/SKILL.md +8 -4
  165. package/runtime/pi/.codex/skills/sync-repos/SKILL.md +8 -4
  166. package/runtime/pi/.codex/skills/task/SKILL.md +9 -5
  167. package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
  168. package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +8 -4
  169. package/runtime/pi/.codex/skills/telemetry/SKILL.md +8 -4
  170. package/runtime/pi/.codex/skills/test/SKILL.md +8 -4
  171. package/runtime/pi/.codex/skills/thread/SKILL.md +8 -4
  172. package/runtime/pi/.codex/skills/todo/SKILL.md +8 -4
  173. package/runtime/pi/.codex/skills/tui-design/SKILL.md +8 -4
  174. package/runtime/pi/.codex/skills/tutorial/SKILL.md +8 -4
  175. package/runtime/pi/.codex/skills/update/SKILL.md +8 -4
  176. package/runtime/pi/.codex/skills/visual-explain/SKILL.md +8 -4
  177. package/runtime/pi/.codex/spec-manifest.json +4 -4
  178. package/runtime/pi/.pi/APPEND_SYSTEM.md +34 -12
  179. package/runtime/pi/.pi/extensions/egregore.ts +8 -1
  180. package/runtime/pi/.pi/spec-manifest.json +2 -2
  181. package/runtime/pi/AGENTS.md +36 -14
  182. package/runtime/pi/bin/activity-data.sh +1 -1
  183. package/runtime/pi/bin/agent.sh +38 -19
  184. package/runtime/pi/bin/attendant.sh +8 -2
  185. package/runtime/pi/bin/autosave.sh +1 -1
  186. package/runtime/pi/bin/capture-reconcile.sh +8 -6
  187. package/runtime/pi/bin/capture-run.sh +1 -1
  188. package/runtime/pi/bin/codex-install-skills.sh +1 -1
  189. package/runtime/pi/bin/codex-render-spec.mjs +12 -5
  190. package/runtime/pi/bin/codex-session-start.sh +1 -1
  191. package/runtime/pi/bin/codex-sync-skills.sh +9 -5
  192. package/runtime/pi/bin/dashboard-data.sh +1 -1
  193. package/runtime/pi/bin/graph-batch.sh +1 -1
  194. package/runtime/pi/bin/graph-op.sh +1 -1
  195. package/runtime/pi/bin/graph-wal.sh +1 -1
  196. package/runtime/pi/bin/graph.sh +1 -1
  197. package/runtime/pi/bin/handoff-pr-backfill.sh +1 -1
  198. package/runtime/pi/bin/handoff-run.sh +53 -39
  199. package/runtime/pi/bin/handoff-save-egregore.sh +62 -32
  200. package/runtime/pi/bin/index-handoff.sh +1 -1
  201. package/runtime/pi/bin/ingest-graph.sh +1 -1
  202. package/runtime/pi/bin/ingest.sh +1 -1
  203. package/runtime/pi/bin/lib/artifact-id.sh +1 -1
  204. package/runtime/pi/bin/lib/config.sh +56 -20
  205. package/runtime/pi/bin/lib/context.sh +7 -1
  206. package/runtime/pi/bin/lib/ensure-develop.sh +1 -1
  207. package/runtime/pi/bin/lib/git-sync.sh +145 -59
  208. package/runtime/pi/bin/lib/greeting.sh +14 -0
  209. package/runtime/pi/bin/lib/hash.sh +1 -1
  210. package/runtime/pi/bin/lib/noncode.sh +1 -1
  211. package/runtime/pi/bin/lib/time.sh +1 -1
  212. package/runtime/pi/bin/notify.sh +492 -153
  213. package/runtime/pi/bin/person.sh +1 -1
  214. package/runtime/pi/bin/pi-session-start.sh +1 -1
  215. package/runtime/pi/bin/publish-artifact.sh +39 -4
  216. package/runtime/pi/bin/publish-references.sh +1 -1
  217. package/runtime/pi/bin/repo-state.sh +7 -10
  218. package/runtime/pi/bin/search.sh +1 -1
  219. package/runtime/pi/bin/session-autosave.sh +1 -1
  220. package/runtime/pi/bin/session-log.sh +1 -1
  221. package/runtime/pi/bin/settings.sh +32 -2
  222. package/runtime/pi/bin/telemetry.sh +1 -1
  223. package/runtime/pi/bin/worktree-create.sh +14 -4
  224. package/runtime/pi/bin/worktree-remove.sh +1 -1
  225. package/runtime/pi/bin/worktree.sh +1 -1
  226. package/runtime/pi/manifest.json +18 -1
@@ -179,11 +179,18 @@ const ON_LAUNCH_BODY = `The \`egregore\` launcher renders the Egregore startup c
179
179
 
180
180
  const AFTER_GREETING_BODY = `**Mandatory behavioral rule.** When the user describes work, your **first action** — before reading files, exploring code, or anything else — is to get onto a working branch:
181
181
 
182
+ The integration branch is \`develop\` by default. When top-level
183
+ \`egregore.json.base_branch\` is set, that configured branch replaces
184
+ \`develop\` as the branch point, rebase target, PR base, and protected
185
+ integration branch.
186
+
182
187
  1. Derive a topic slug from what the user said (kebab-case, 2–4 words)
183
- 2. Run \`bin/agent.sh branch --topic "<topic>"\` — it creates a work branch from \`origin/develop\` in a task worktree (\`dev/{author}/{slug}\`, or \`feature/{slug}\` / \`bugfix/{slug}\` when the topic reads as a feature or fix) and prints the worktree path. Continue all file work from that printed path.
188
+ 2. Run \`bin/agent.sh branch --topic "<topic>"\` — it resolves the configured base and creates a work branch from \`origin/{base}\` in a task worktree (\`dev/{author}/{slug}\`, or \`feature/{slug}\` / \`bugfix/{slug}\` when the topic reads as a feature or fix). Continue all file work from the printed path.
184
189
  3. Confirm: \`On {branch} (worktree).\`
185
190
 
186
- **Fallback:** If \`bin/agent.sh branch\` fails, use \`git checkout -b dev/{author}/{slug} origin/develop\`.
191
+ **Fallback:** If \`bin/agent.sh branch\` fails, resolve \`{base}\` with
192
+ \`_get_base_branch\`, then use
193
+ \`git checkout -b dev/{author}/{slug} origin/{base}\`.
187
194
 
188
195
  4. Update graph (fire-and-forget): \`bash bin/graph-op.sh set-topic "$(cat .egregore-session-id 2>/dev/null)" "topic from slug" "dev/author/slug" 2>/dev/null &\`
189
196
 
@@ -215,11 +222,11 @@ Report results: \`✓ Checked out {branch} in {repo1}, {repo2}\`. If a branch no
215
222
 
216
223
  **Topic pivot while on a working branch:** If the user describes work **unrelated** to the current branch's topic, treat it as a new topic and create a new branch (\`bin/agent.sh branch --topic "<new topic>"\`). Do NOT mix unrelated work on one branch.
217
224
 
218
- If on develop after two messages, create a branch immediately from whatever context you have.
225
+ If still on the configured base branch after two messages, create a branch immediately from whatever context you have.
219
226
 
220
227
  ### Branch-guard protocol
221
228
 
222
- The \`.codex/hooks/branch-guard.js\` PreToolUse hook (enabled by the launcher via \`--enable hooks\`) protects project writes on \`develop\`/\`main\`/\`master\`. Its block message is operational guidance, not a reason to interrupt the user with routine Git choices:
229
+ The \`.codex/hooks/branch-guard.js\` PreToolUse hook (enabled by the launcher via \`--enable hooks\`) protects project writes on the configured base branch as well as \`develop\`/\`main\`/\`master\`. Its block message is operational guidance, not a reason to interrupt the user with routine Git choices:
223
230
 
224
231
  - **Topic is clear** (the user said "fix X", "add Y feature") → run \`bin/agent.sh branch --topic "<topic>"\` automatically, continue in the printed worktree, and say one short sentence so the branch change is visible. Do not ask the user to approve routine branching.
225
232
  - **Topic is genuinely ambiguous** → ask only for the topic, using compact numbered options:
@@ -236,7 +243,7 @@ The \`.codex/hooks/branch-guard.js\` PreToolUse hook (enabled by the launcher vi
236
243
 
237
244
  Memory, managed-repo, and runtime-state writes should bypass the project guard. If one triggers it, correct the operation target/context instead of asking for protected-branch consent.
238
245
 
239
- If this Codex build does not support hooks, follow the same discipline as a standing instruction: never write or commit on develop/main/master.
246
+ If this Codex build does not support hooks, follow the same discipline as a standing instruction: never write or commit on the configured base, develop, main, or master.
240
247
 
241
248
  ### Onboarding exception
242
249
 
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -o pipefail
3
3
 
4
4
  # Codex does not run Claude Code SessionStart hooks. This is the runtime-neutral
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
@@ -162,11 +162,15 @@ EOF
162
162
  cat <<EOF
163
163
  1. Read \`${source}\` for the workflow details.
164
164
  2. Run the referenced \`bin/\` scripts directly from Codex.
165
- 3. Treat graph, publish, and notify steps as best-effort unless that workflow
166
- explicitly says they are required.
167
- 4. Keep local-mode behavior filesystem-first and avoid graph or notification
165
+ 3. Treat graph and publish steps as best-effort unless that workflow explicitly
166
+ says they are required.
167
+ 4. For every external notification, follow
168
+ \`.claude/context/notification-consent.md\`: plan without sending, then show
169
+ a separate exact Send / Edit / Cancel checkpoint. Never infer notification
170
+ consent from the workflow request or a batch approval.
171
+ 5. Keep local-mode behavior filesystem-first and avoid graph or notification
168
172
  calls when \`egregore.json\` declares \`"mode": "local"\`.
169
- 5. Never call the deprecated \`egregore-handoff\` CLI for Egregore project
173
+ 6. Never call the deprecated \`egregore-handoff\` CLI for Egregore project
170
174
  handoffs.
171
175
  EOF
172
176
  }
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # Fetches personal dashboard data: single API call + parallel git ops.
3
3
  # Usage: bash bin/dashboard-data.sh [username] [time_range]
4
4
  # Returns a single JSON object with all query results.
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  # Execute multiple Cypher queries in a single HTTP call.
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
  # Named graph operations — clean interface over raw Cypher.
4
4
  # Keeps implementation details out of the TUI.
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # Graph Write-Ahead Log — resilient graph writes with local buffer.
3
3
  # Mirrors bin/telemetry.sh architecture.
4
4
  #
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # handoff-pr-backfill.sh — fill in PR numbers in a handoff file's ## Repo State
3
3
  # table, then re-commit + push the memory repo. Detached fire-and-forget from
4
4
  # /handoff's hot path so user-visible latency doesn't include N × `gh pr list`.
@@ -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:
@@ -231,14 +231,14 @@ awk -v line="$IDX_LINE" '
231
231
  END { if (!inserted) print line }
232
232
  ' "$INDEX" > "$INDEX.new" && mv "$INDEX.new" "$INDEX"
233
233
 
234
- # --- Parallel stage: graph + memory + (publish → notify) ----------------
234
+ # --- Parallel stage: graph + memory + (publish → notification proposal) -
235
235
  #
236
236
  # Three independent branches fork here and join before we emit the result:
237
237
  # A. Graph index — reads ABS_FILE, writes Session node to Neo4j, and
238
238
  # returns the handoff's neighborhood as subgraph JSON.
239
239
  # 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.
240
+ # C. Publish+plan — publishes HTML artifact, then creates an immutable
241
+ # notification proposal with the artifact URL embedded.
242
242
  #
243
243
  # Each branch writes its result to a tmpfile. Wall-clock is max(A,B,C).
244
244
  #
@@ -251,7 +251,7 @@ MEMORY_DIR="$SCRIPT_DIR/memory"
251
251
  TMPD=$(mktemp -d -t handoff-run-XXXXXX)
252
252
  trap 'rm -rf "$TMPD"' EXIT
253
253
 
254
- # Extract briefing text once (used by publish and notify) so we don't
254
+ # Extract briefing text once (used by publish and the proposal) so we don't
255
255
  # re-awk the same file inside multiple workers.
256
256
  BRIEFING_LEAD=$(awk '/^## Briefing/{found=1; next} found && /^##/{exit} found && NF{print}' "$ABS_FILE" 2>/dev/null \
257
257
  | head -2 | tr '\n' ' ' | cut -c1-200 || true)
@@ -390,7 +390,11 @@ PID_MEMORY=$!
390
390
  fi
391
391
  EMISSARY_API_URL="${EMISSARY_API_URL:-https://egregore-production-55f2.up.railway.app/api/v1/emissary}"
392
392
 
393
- if [ -n "$EMISSARY_TOKEN" ]; then
393
+ # /handoff is an internal team primitive, not an implicit public-emissary
394
+ # composer. Use the emissary route only for an explicit recipient, and make
395
+ # that artifact directed-private. Recipient-less handoffs fall through to
396
+ # the org-scoped publisher (connected) or opt-in relay (local).
397
+ if [ -n "$EMISSARY_TOKEN" ] && [ -n "$RECIPIENT" ]; then
394
398
  # Step 1: render the handoff to HTML locally using egregore-artifacts.
395
399
  # Same renderer + template publish-artifact.sh uses today — handoffs
396
400
  # keep their familiar look.
@@ -422,12 +426,8 @@ PID_MEMORY=$!
422
426
  DISPLAY_NAME=$(head -1 "$PERSON_FILE" | sed 's/^# //')
423
427
  fi
424
428
 
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
429
+ RECIP_HANDLE=$(echo "$RECIPIENT" | tr '[:upper:]' '[:lower:]' | awk '{print $1}')
430
+ ADDRESSED_TO=$(jq -nc --arg h "$RECIP_HANDLE" --arg d "$RECIPIENT" '[{"handle":$h,"display":$d}]')
431
431
 
432
432
  CLAIM=$(echo "$BRIEFING_LEAD" | cut -c1-200)
433
433
 
@@ -456,8 +456,8 @@ PID_MEMORY=$!
456
456
  body: { prose: $prose },
457
457
  audience: {
458
458
  addressed_to: $addressed,
459
- visible_to: "public",
460
- extendable_by: "anyone"
459
+ visible_to: $addressed,
460
+ extendable_by: $addressed
461
461
  },
462
462
  parents: [],
463
463
  render_mode: "custom",
@@ -475,15 +475,30 @@ PID_MEMORY=$!
475
475
  fi
476
476
  fi
477
477
 
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.
478
+ # Fallback: if a directed emissary publish didn't produce a URL—or this is a
479
+ # recipient-less team handoff—use publish-artifact.sh. Connected mode is
480
+ # authenticated and org-scoped; local mode's public relay is opt-in.
481
+ PUBLISH_RC=0
481
482
  if [ -z "$V1URL" ] && [ "$NO_PUBLISH" = "0" ] && [ -x "$SCRIPT_DIR/bin/publish-artifact.sh" ]; then
482
483
  AURL=$(bash "$SCRIPT_DIR/bin/publish-artifact.sh" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" \
483
484
  --title "$TOPIC" \
484
485
  --author "$AUTHOR" \
485
- --description "$BRIEFING_LEAD" 2>/dev/null || echo "")
486
+ --description "$BRIEFING_LEAD" 2>/dev/null) || PUBLISH_RC=$?
487
+ fi
488
+
489
+ PS="published"
490
+ if [ "$NO_PUBLISH" = "1" ]; then
491
+ PS="disabled"
492
+ elif [ -n "$V1URL" ] || [ -n "$AURL" ]; then
493
+ PS="published"
494
+ elif [ "$PUBLISH_RC" = "4" ]; then
495
+ PS="relay-off"
496
+ elif [ "$PUBLISH_RC" = "3" ]; then
497
+ PS="hosting-off"
498
+ else
499
+ PS="failed"
486
500
  fi
501
+ echo "$PS" > "$TMPD/publish"
487
502
 
488
503
  # Prefer v1 (emissary-rendered) URL when available; fall back to the
489
504
  # legacy egregore-artifacts URL only if the v1 publish failed.
@@ -497,6 +512,7 @@ PID_MEMORY=$!
497
512
  fi
498
513
 
499
514
  NS="skipped"
515
+ echo '{}' > "$TMPD/notify-plan"
500
516
  if [ "$NO_NOTIFY" = "0" ]; then
501
517
  if [ -n "$NOTIFY_URL" ]; then
502
518
  MSG_NOTIFY="Handoff from ${AUTHOR}: ${TOPIC}
@@ -510,21 +526,19 @@ View: ${NOTIFY_URL}"
510
526
  \"${BRIEFING_SHORT}\""
511
527
  fi
512
528
 
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")
529
+ # Resolve the exact destination, but never approve or dispatch here. The
530
+ # interactive harness must show this proposal in a separate checkpoint.
531
+ if [ -n "$RECIPIENT" ]; then
532
+ NR=$(bash "$SCRIPT_DIR/bin/notify.sh" plan send "$RECIPIENT" "$MSG_NOTIFY" 2>/dev/null || echo '{}')
518
533
  else
519
- NR=$(bash "$SCRIPT_DIR/bin/notify.sh" group "$MSG_NOTIFY" 2>/dev/null || echo "Failed")
534
+ NR=$(bash "$SCRIPT_DIR/bin/notify.sh" plan group "$MSG_NOTIFY" 2>/dev/null || echo '{}')
520
535
  fi
521
536
 
522
- if echo "$NR" | grep -qi "^Sent"; then
523
- NS="sent"
524
- elif echo "$NR" | grep -qi "^Failed"; then
525
- NS="failed"
537
+ if printf '%s' "$NR" | jq -e '.status == "approval_required"' >/dev/null 2>&1; then
538
+ NS="approval_required"
539
+ printf '%s\n' "$NR" > "$TMPD/notify-plan"
526
540
  else
527
- NS="unknown"
541
+ NS="unavailable"
528
542
  fi
529
543
  fi
530
544
  echo "$NS" > "$TMPD/notify"
@@ -574,6 +588,9 @@ fi
574
588
  MEMORY_STATUS=$(cat "$TMPD/memory" 2>/dev/null || echo "skipped")
575
589
  ARTIFACT_URL=$(cat "$TMPD/artifact" 2>/dev/null || echo "")
576
590
  NOTIFY_STATUS=$(cat "$TMPD/notify" 2>/dev/null || echo "skipped")
591
+ NOTIFY_PLAN=$(cat "$TMPD/notify-plan" 2>/dev/null || echo "{}")
592
+ PUBLISH_STATUS=$(cat "$TMPD/publish" 2>/dev/null || echo "skipped")
593
+ [ -z "$PUBLISH_STATUS" ] && PUBLISH_STATUS="skipped"
577
594
  ARTIFACTS_ARR=$(cat "$TMPD/artifacts" 2>/dev/null || echo "[]")
578
595
  [ -z "$ARTIFACTS_ARR" ] && ARTIFACTS_ARR="[]"
579
596
 
@@ -594,16 +611,9 @@ fi
594
611
  STATUS_BITS=("saved")
595
612
  [ "$GRAPH_STATUS" = "ok" ] && STATUS_BITS+=("graphed")
596
613
  [ "$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
614
+ [ "$NOTIFY_STATUS" = "approval_required" ] && STATUS_BITS+=("notify approval pending")
606
615
  [ -n "$ARTIFACT_URL" ] && STATUS_BITS+=("published")
616
+ [ "$PUBLISH_STATUS" = "relay-off" ] && STATUS_BITS+=("not published")
607
617
 
608
618
  STATUS_LINE=""
609
619
  for bit in "${STATUS_BITS[@]}"; do
@@ -625,7 +635,9 @@ jq -cn \
625
635
  --arg graphStatus "$GRAPH_STATUS" \
626
636
  --arg memoryStatus "$MEMORY_STATUS" \
627
637
  --arg notifyStatus "$NOTIFY_STATUS" \
638
+ --argjson notifyPlan "$NOTIFY_PLAN" \
628
639
  --arg artifactUrl "$ARTIFACT_URL" \
640
+ --arg publishStatus "$PUBLISH_STATUS" \
629
641
  --arg recipient "$RECIPIENT" \
630
642
  --arg topic "$TOPIC" \
631
643
  --arg author "$AUTHOR" \
@@ -640,7 +652,9 @@ jq -cn \
640
652
  graphStatus:$graphStatus,
641
653
  memoryStatus:$memoryStatus,
642
654
  notifyStatus:$notifyStatus,
655
+ notifyPlan:$notifyPlan,
643
656
  artifactUrl:$artifactUrl,
657
+ publishStatus:$publishStatus,
644
658
  recipient:$recipient,
645
659
  topic:$topic,
646
660
  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.
@@ -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
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # Shared config helpers — sourced by session-start.sh and other scripts.
3
3
  # Expects SCRIPT_DIR to be set by the caller.
4
4
 
@@ -25,35 +25,71 @@ _config_val() {
25
25
  fi
26
26
  }
27
27
 
28
- # Get base branch for a repo. Reads base_branch from egregore.json repos[] config.
29
- # Defaults to "develop" for backwards compatibility (existing egregores use develop).
30
- # Only returns something other than "develop" when base_branch is explicitly set
31
- # (e.g., for teams who added existing repos with a different default branch).
28
+ # Get base branch for a repo. Reads base_branch from egregore.json — top-level
29
+ # for the core egregore repo, per-entry under repos[] for managed repos.
30
+ # Defaults to "develop" for backwards compatibility only when a valid config
31
+ # omits the setting. Missing, unreadable, malformed, or invalid config fails:
32
+ # callers must never turn a config read failure into a remote branch mutation.
33
+ #
34
+ # Setting a top-level "base_branch": "main" is single-branch mode: the whole
35
+ # develop layer disappears and everything (session start, sync, the branch
36
+ # guard, PR bases) targets main instead. Solo operators who never wanted the
37
+ # develop/main split had no way to say so — the core repo used to be hardcoded
38
+ # even though managed repos were already configurable.
39
+ #
32
40
  # Usage: _get_base_branch "repo-name" (omit for core repo)
33
41
  _get_base_branch() {
34
42
  local repo_name="${1:-}"
35
43
  local config="${CONFIG:-$SCRIPT_DIR/egregore.json}"
44
+ local base=""
36
45
 
37
- # Core egregore repo — always develop
38
- if [ -z "$repo_name" ]; then
39
- echo "develop"
40
- return
46
+ if [ ! -r "$config" ]; then
47
+ echo "config: cannot read $config" >&2
48
+ return 1
49
+ fi
50
+ if ! jq -e 'type == "object"' "$config" >/dev/null 2>&1; then
51
+ echo "config: invalid JSON object in $config" >&2
52
+ return 1
41
53
  fi
42
54
 
43
- # Managed repo — check egregore.json for explicit base_branch
44
- if [ -f "$config" ]; then
45
- local base
46
- base=$(jq -r --arg name "$repo_name" \
47
- '(.repos[]? // empty) | select((if type == "object" then .name else . end) == $name) | if type == "object" then .base_branch // empty else empty end' \
48
- "$config" 2>/dev/null || true)
49
- if [ -n "$base" ]; then
50
- echo "$base"
51
- return
55
+ if [ -z "$repo_name" ]; then
56
+ # Core egregore repo — top-level base_branch. An absent value preserves
57
+ # the historical develop default; an explicitly invalid value is an error.
58
+ if jq -e 'has("base_branch")' "$config" >/dev/null 2>&1; then
59
+ if ! base=$(jq -er '.base_branch | select(type == "string")' "$config" 2>/dev/null); then
60
+ echo "config: base_branch must be a valid branch name" >&2
61
+ return 1
62
+ fi
63
+ else
64
+ base="develop"
65
+ fi
66
+ else
67
+ # Managed repo — its own entry under repos[]. Unknown/string-form entries
68
+ # retain the historical develop default.
69
+ local repo_json
70
+ repo_json=$(jq -c --arg name "$repo_name" \
71
+ 'first(.repos[]? | select((if type == "object" then .name else . end) == $name)) // null' \
72
+ "$config" 2>/dev/null) || {
73
+ echo "config: cannot resolve managed repo $repo_name" >&2
74
+ return 1
75
+ }
76
+ if [ "$repo_json" != "null" ] \
77
+ && [ "$(printf '%s' "$repo_json" | jq -r 'type')" = "object" ] \
78
+ && printf '%s' "$repo_json" | jq -e 'has("base_branch")' >/dev/null 2>&1; then
79
+ if ! base=$(printf '%s' "$repo_json" | jq -er '.base_branch | select(type == "string")' 2>/dev/null); then
80
+ echo "config: base_branch for $repo_name must be a valid branch name" >&2
81
+ return 1
82
+ fi
83
+ else
84
+ base="develop"
52
85
  fi
53
86
  fi
54
87
 
55
- # No explicit config — default to develop (backwards compatible)
56
- echo "develop"
88
+ if [ -z "$base" ] || ! git check-ref-format --branch "$base" >/dev/null 2>&1; then
89
+ echo "config: base_branch must be a valid branch name" >&2
90
+ return 1
91
+ fi
92
+ echo "$base"
57
93
  }
58
94
 
59
95
  # Detect local vs connected mode