create-egregore 0.19.32 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/egregore-launcher.js +118 -13
- package/bin/cli.js +48 -3
- package/lib/connect-runtime.js +4 -2
- package/lib/local.js +15 -1
- package/lib/prime-runtime.js +208 -0
- package/lib/setup.js +45 -3
- package/package.json +5 -4
- package/runtime/codex/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/codex/.codex/spec-manifest.json +3 -3
- package/runtime/codex/AGENTS.md +11 -4
- package/runtime/codex/bin/activity-data.sh +4 -8
- package/runtime/codex/bin/attendant.sh +13 -0
- package/runtime/codex/bin/autosave.sh +27 -1
- package/runtime/codex/bin/codex-render-spec.mjs +6 -0
- package/runtime/codex/bin/codex-session-start.sh +8 -1
- package/runtime/codex/bin/connect-refresh.sh +33 -0
- package/runtime/codex/bin/graph-batch.sh +25 -6
- package/runtime/codex/bin/graph-op.sh +5 -4
- package/runtime/codex/bin/graph.sh +31 -5
- package/runtime/codex/bin/ingest.py +81 -5
- package/runtime/codex/bin/lib/context.sh +26 -1
- package/runtime/codex/bin/lib/greeting.sh +4 -1
- package/runtime/codex/bin/lib/worktree-links.sh +25 -0
- package/runtime/codex/manifest.json +8 -1
- package/runtime/pi/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/pi/.codex/spec-manifest.json +3 -3
- package/runtime/pi/.pi/APPEND_SYSTEM.md +3 -2
- package/runtime/pi/.pi/extensions/egregore.ts +17 -6
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +11 -4
- package/runtime/pi/bin/activity-data.sh +4 -8
- package/runtime/pi/bin/attendant.sh +13 -0
- package/runtime/pi/bin/autosave.sh +27 -1
- package/runtime/pi/bin/codex-render-spec.mjs +6 -0
- package/runtime/pi/bin/codex-session-start.sh +8 -1
- package/runtime/pi/bin/connect-refresh.sh +33 -0
- package/runtime/pi/bin/graph-batch.sh +25 -6
- package/runtime/pi/bin/graph-op.sh +5 -4
- package/runtime/pi/bin/graph.sh +31 -5
- package/runtime/pi/bin/ingest.py +81 -5
- package/runtime/pi/bin/lib/context.sh +26 -1
- package/runtime/pi/bin/lib/greeting.sh +4 -1
- package/runtime/pi/bin/lib/worktree-links.sh +25 -0
- package/runtime/pi/bin/pi-branch-policy.mjs +138 -1
- package/runtime/pi/bin/pi-product-workflows.mjs +35 -7
- package/runtime/pi/manifest.json +8 -1
- package/runtime/prime/.claude/context/notification-consent.md +66 -0
- package/runtime/prime/.codex/config.toml +17 -0
- package/runtime/prime/.codex/hooks/branch-guard.js +461 -0
- package/runtime/prime/.codex/hooks/search-hint.js +67 -0
- package/runtime/prime/.codex/hooks.json +30 -0
- package/runtime/prime/.codex/skills/activity/SKILL.md +82 -0
- package/runtime/prime/.codex/skills/announce/SKILL.md +67 -0
- package/runtime/prime/.codex/skills/archive/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/branch/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/checkup/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/commit/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/contribute/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/create-skill/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dark-mode/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/dashboard/SKILL.md +59 -0
- package/runtime/prime/.codex/skills/deep-reflect/SKILL.md +109 -0
- package/runtime/prime/.codex/skills/delete-user/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/emissary/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/handoff/SKILL.md +166 -0
- package/runtime/prime/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
- package/runtime/prime/.codex/skills/harvest/SKILL.md +131 -0
- package/runtime/prime/.codex/skills/ingest/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-notion/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/invite/SKILL.md +44 -0
- package/runtime/prime/.codex/skills/issue/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/me/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/meeting/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/note/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/notion-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/onboarding/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/pr/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/pull/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/push/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/quest/SKILL.md +80 -0
- package/runtime/prime/.codex/skills/reflect/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/review-pr/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/save/SKILL.md +125 -0
- package/runtime/prime/.codex/skills/slack-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/summon/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/sync-repos/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/teams-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telegram-connect/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/telemetry/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/test/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/the-spiral/SKILL.md +84 -0
- package/runtime/prime/.codex/skills/tui-design/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/tutorial/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/update/SKILL.md +29 -0
- package/runtime/prime/.codex/skills/view/SKILL.md +156 -0
- package/runtime/prime/.codex/skills/view/agents/openai.yaml +4 -0
- package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +221 -0
- package/runtime/prime/.codex/skills/visual-explain/SKILL.md +45 -0
- package/runtime/prime/.codex/skills/wrap/SKILL.md +58 -0
- package/runtime/prime/.codex/spec-manifest.json +132 -0
- package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +393 -0
- package/runtime/prime/.prime/agent/extensions/egregore.ts +460 -0
- package/runtime/prime/.prime/agent/settings.json +4 -0
- package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +34 -0
- package/runtime/prime/.prime/agent/skills/egregore/pyproject.toml +13 -0
- package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +156 -0
- package/runtime/prime/.prime/agent/spec-manifest.json +12 -0
- package/runtime/prime/AGENTS.md +489 -0
- package/runtime/prime/bin/activity-data.sh +238 -0
- package/runtime/prime/bin/agent.sh +775 -0
- package/runtime/prime/bin/attendant.sh +707 -0
- package/runtime/prime/bin/autosave.sh +112 -0
- package/runtime/prime/bin/capture-reconcile.sh +69 -0
- package/runtime/prime/bin/capture-run.sh +341 -0
- package/runtime/prime/bin/codex-install-skills.sh +78 -0
- package/runtime/prime/bin/codex-render-spec.mjs +440 -0
- package/runtime/prime/bin/codex-session-start.sh +265 -0
- package/runtime/prime/bin/codex-skill-render.mjs +347 -0
- package/runtime/prime/bin/codex-sync-skills.sh +232 -0
- package/runtime/prime/bin/connect-refresh.sh +33 -0
- package/runtime/prime/bin/dashboard-data.sh +178 -0
- package/runtime/prime/bin/graph-batch.sh +79 -0
- package/runtime/prime/bin/graph-op.sh +1102 -0
- package/runtime/prime/bin/graph-wal.sh +229 -0
- package/runtime/prime/bin/graph.sh +223 -0
- package/runtime/prime/bin/handoff-pr-backfill.sh +86 -0
- package/runtime/prime/bin/handoff-run.sh +671 -0
- package/runtime/prime/bin/handoff-save-egregore.sh +212 -0
- package/runtime/prime/bin/index-handoff.sh +322 -0
- package/runtime/prime/bin/ingest-graph.sh +80 -0
- package/runtime/prime/bin/ingest-surface.html +495 -0
- package/runtime/prime/bin/ingest.py +756 -0
- package/runtime/prime/bin/ingest.sh +279 -0
- package/runtime/prime/bin/ingest_graph.py +856 -0
- package/runtime/prime/bin/ingest_surface.py +544 -0
- package/runtime/prime/bin/lib/artifact-id.sh +46 -0
- package/runtime/prime/bin/lib/config.sh +116 -0
- package/runtime/prime/bin/lib/context.sh +621 -0
- package/runtime/prime/bin/lib/dashboard-artifact.sh +242 -0
- package/runtime/prime/bin/lib/ensure-develop.sh +183 -0
- package/runtime/prime/bin/lib/git-sync.sh +406 -0
- package/runtime/prime/bin/lib/greeting.sh +519 -0
- package/runtime/prime/bin/lib/hash.sh +13 -0
- package/runtime/prime/bin/lib/identity.sh +213 -0
- package/runtime/prime/bin/lib/metrics.sh +374 -0
- package/runtime/prime/bin/lib/noncode.sh +31 -0
- package/runtime/prime/bin/lib/permissions.sh +106 -0
- package/runtime/prime/bin/lib/time.sh +56 -0
- package/runtime/prime/bin/lib/worktree-links.sh +79 -0
- package/runtime/prime/bin/notify.sh +636 -0
- package/runtime/prime/bin/person.py +630 -0
- package/runtime/prime/bin/person.sh +448 -0
- package/runtime/prime/bin/pi-branch-policy.mjs +312 -0
- package/runtime/prime/bin/pi-product-workflows.mjs +394 -0
- package/runtime/prime/bin/prime-render-spec.mjs +123 -0
- package/runtime/prime/bin/prime-session-start.sh +24 -0
- package/runtime/prime/bin/publish-artifact.sh +271 -0
- package/runtime/prime/bin/publish-references.sh +144 -0
- package/runtime/prime/bin/repo-state.sh +96 -0
- package/runtime/prime/bin/search.sh +240 -0
- package/runtime/prime/bin/session-autosave.sh +209 -0
- package/runtime/prime/bin/session-log.sh +199 -0
- package/runtime/prime/bin/settings.sh +304 -0
- package/runtime/prime/bin/telemetry.sh +391 -0
- package/runtime/prime/bin/worktree-create.sh +128 -0
- package/runtime/prime/bin/worktree-remove.sh +50 -0
- package/runtime/prime/bin/worktree.sh +198 -0
- package/runtime/prime/manifest.json +178 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Runtime-neutral Egregore agent bridge.
|
|
3
|
+
#
|
|
4
|
+
# This script exposes the Git-backed memory protocol without requiring
|
|
5
|
+
# Claude Code hooks or slash-command skills. Any agent runtime that can run
|
|
6
|
+
# shell commands inside an Egregore checkout can use it to sync memory,
|
|
7
|
+
# create handoffs, ask questions, answer questions, and inspect activity.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
11
|
+
MAIN_PROJECT_DIR="$SCRIPT_DIR"
|
|
12
|
+
if [ -f "$SCRIPT_DIR/.git" ]; then
|
|
13
|
+
WT_GITDIR=$(sed 's/^gitdir: //' "$SCRIPT_DIR/.git" 2>/dev/null || true)
|
|
14
|
+
[ -n "$WT_GITDIR" ] && MAIN_PROJECT_DIR=$(cd "$WT_GITDIR/../../.." 2>/dev/null && pwd || echo "$SCRIPT_DIR")
|
|
15
|
+
fi
|
|
16
|
+
if [ -f "$SCRIPT_DIR/bin/lib/worktree-links.sh" ]; then
|
|
17
|
+
source "$SCRIPT_DIR/bin/lib/worktree-links.sh" >/dev/null 2>/dev/null || true
|
|
18
|
+
egregore_link_shared_state "$SCRIPT_DIR" "$MAIN_PROJECT_DIR" >/dev/null 2>/dev/null || true
|
|
19
|
+
fi
|
|
20
|
+
CONFIG="$SCRIPT_DIR/egregore.json"
|
|
21
|
+
MEMORY_DIR="${EGREGORE_MEMORY_DIR:-$SCRIPT_DIR/memory}"
|
|
22
|
+
if [ -f "$SCRIPT_DIR/bin/lib/config.sh" ]; then
|
|
23
|
+
# shellcheck source=bin/lib/config.sh
|
|
24
|
+
source "$SCRIPT_DIR/bin/lib/config.sh"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
usage() {
|
|
28
|
+
cat <<'EOF'
|
|
29
|
+
Usage: agent.sh <command> [options]
|
|
30
|
+
|
|
31
|
+
Runtime-neutral commands:
|
|
32
|
+
protocol Print the portable agent protocol
|
|
33
|
+
sync Pull latest shared memory
|
|
34
|
+
activity [--for <person>] Show recent handoffs and questions
|
|
35
|
+
search "query" [-n N] [--fast|--semantic]
|
|
36
|
+
Hybrid recall over shared memory (qmd)
|
|
37
|
+
people List known people from memory/people
|
|
38
|
+
branch --topic TEXT Create or reuse a task branch/worktree
|
|
39
|
+
save [--message TEXT] [--pr-body TEXT|--pr-body-file PATH]
|
|
40
|
+
Commit and push current repo + memory changes;
|
|
41
|
+
PR body follows .claude/context/pr-format.md
|
|
42
|
+
(auto-generated skeleton if not provided)
|
|
43
|
+
autosave [status|on|off|scope|publish|merge] Personal ambient-save settings + consent
|
|
44
|
+
wrap --topic T --summary TEXT Write a session wrap to memory/wraps
|
|
45
|
+
handoff --from A --to B --topic T [--intent action|feedback|fyi]
|
|
46
|
+
[--body TEXT|--body-file PATH] [--no-push] [--no-publish] [--no-notify] [--json]
|
|
47
|
+
ask --from A --to B --topic T --question TEXT [--no-push]
|
|
48
|
+
[--harvest-id ID --harvest-session-id ID --turn N
|
|
49
|
+
--question-intent TEXT --context-mode blind|disclosed|comparative]
|
|
50
|
+
answer --from A --question PATH --body TEXT [--no-push]
|
|
51
|
+
|
|
52
|
+
The script uses the existing memory/ repository and keeps Claude Code
|
|
53
|
+
behavior unchanged.
|
|
54
|
+
EOF
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
die() {
|
|
58
|
+
echo "agent.sh: $*" >&2
|
|
59
|
+
exit 1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
resolve_base_branch() {
|
|
63
|
+
local base
|
|
64
|
+
if ! base=$(_get_base_branch); then
|
|
65
|
+
echo "agent.sh: could not resolve the configured base branch" >&2
|
|
66
|
+
return 1
|
|
67
|
+
fi
|
|
68
|
+
echo "$base"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
slugify() {
|
|
72
|
+
echo "$1" \
|
|
73
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
74
|
+
| sed -E 's/[^a-z0-9]+/-/g' \
|
|
75
|
+
| sed -E 's/^-+|-+$//g' \
|
|
76
|
+
| cut -c1-60
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Reject control characters that would break YAML frontmatter when interpolated.
|
|
80
|
+
reject_newlines() {
|
|
81
|
+
case "$2" in
|
|
82
|
+
*$'\n'*|*$'\r'*) die "invalid $1: must not contain newlines" ;;
|
|
83
|
+
esac
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Emit a value as a JSON-encoded string (valid YAML), so colons, quotes,
|
|
87
|
+
# and other YAML metacharacters in user-supplied values cannot inject keys.
|
|
88
|
+
yaml_str() {
|
|
89
|
+
jq -n --arg v "$1" '$v'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
ensure_memory() {
|
|
93
|
+
[ -d "$MEMORY_DIR" ] || die "memory directory not found: $MEMORY_DIR"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
is_memory_git() {
|
|
97
|
+
git -C "$MEMORY_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
memory_branch() {
|
|
101
|
+
git -C "$MEMORY_DIR" branch --show-current 2>/dev/null || echo "main"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
sync_memory() {
|
|
105
|
+
ensure_memory
|
|
106
|
+
if is_memory_git && git -C "$MEMORY_DIR" remote get-url origin >/dev/null 2>&1; then
|
|
107
|
+
local branch
|
|
108
|
+
branch="$(memory_branch)"
|
|
109
|
+
[ -z "$branch" ] && branch="main"
|
|
110
|
+
git -C "$MEMORY_DIR" pull --rebase origin "$branch" --quiet 2>/dev/null || true
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
save_memory() {
|
|
115
|
+
local message="$1"
|
|
116
|
+
shift
|
|
117
|
+
local no_push="${NO_PUSH:-0}"
|
|
118
|
+
|
|
119
|
+
ensure_memory
|
|
120
|
+
if ! is_memory_git; then
|
|
121
|
+
return 0
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
git -C "$MEMORY_DIR" add "$@" >/dev/null 2>&1 || true
|
|
125
|
+
if ! git -C "$MEMORY_DIR" diff --cached --quiet 2>/dev/null; then
|
|
126
|
+
git -C "$MEMORY_DIR" commit -m "$message" --quiet 2>/dev/null || true
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
[ "$no_push" = "1" ] && return 0
|
|
130
|
+
git -C "$MEMORY_DIR" remote get-url origin >/dev/null 2>&1 || return 0
|
|
131
|
+
|
|
132
|
+
local branch
|
|
133
|
+
branch="$(memory_branch)"
|
|
134
|
+
[ -z "$branch" ] && branch="main"
|
|
135
|
+
for _try in 1 2 3; do
|
|
136
|
+
if git -C "$MEMORY_DIR" pull --rebase origin "$branch" --quiet 2>/dev/null \
|
|
137
|
+
&& git -C "$MEMORY_DIR" push origin "$branch" --quiet 2>/dev/null; then
|
|
138
|
+
return 0
|
|
139
|
+
fi
|
|
140
|
+
sleep 1
|
|
141
|
+
done
|
|
142
|
+
die "could not push memory after 3 attempts"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
person_from_state() {
|
|
146
|
+
if [ -f "$SCRIPT_DIR/.egregore-state.json" ]; then
|
|
147
|
+
jq -r '.github_username // .name // empty' "$SCRIPT_DIR/.egregore-state.json" 2>/dev/null || true
|
|
148
|
+
fi
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
current_author() {
|
|
152
|
+
local author
|
|
153
|
+
author="$(person_from_state)"
|
|
154
|
+
[ -n "$author" ] || author="$(git -C "$SCRIPT_DIR" config user.name 2>/dev/null | awk '{print tolower($1)}')"
|
|
155
|
+
[ -n "$author" ] || author="agent"
|
|
156
|
+
echo "$author"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
worktree_for_branch() {
|
|
160
|
+
local branch="$1"
|
|
161
|
+
git -C "$MAIN_PROJECT_DIR" worktree list --porcelain 2>/dev/null | awk -v ref="refs/heads/$branch" '
|
|
162
|
+
$1 == "worktree" { path = $2 }
|
|
163
|
+
$1 == "branch" && $2 == ref { print path; exit }
|
|
164
|
+
'
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
base_ref() {
|
|
168
|
+
local base
|
|
169
|
+
base="$(resolve_base_branch)" || return 1
|
|
170
|
+
git -C "$MAIN_PROJECT_DIR" fetch origin "$base" --quiet 2>/dev/null || true
|
|
171
|
+
if git -C "$MAIN_PROJECT_DIR" show-ref --verify --quiet "refs/remotes/origin/$base" 2>/dev/null; then
|
|
172
|
+
echo "origin/$base"
|
|
173
|
+
elif git -C "$MAIN_PROJECT_DIR" show-ref --verify --quiet "refs/heads/$base" 2>/dev/null; then
|
|
174
|
+
echo "$base"
|
|
175
|
+
else
|
|
176
|
+
echo "agent.sh: configured base branch '$base' does not exist locally or on origin" >&2
|
|
177
|
+
return 1
|
|
178
|
+
fi
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
cmd_protocol() {
|
|
182
|
+
cat <<'EOF'
|
|
183
|
+
Egregore portable agent protocol
|
|
184
|
+
|
|
185
|
+
1. Work inside an Egregore checkout with a linked memory/ repository.
|
|
186
|
+
2. Run `bin/agent.sh sync` before reading shared state.
|
|
187
|
+
3. Read `memory/people/` for collaborators.
|
|
188
|
+
4. Use `bin/agent.sh handoff` to leave structured context for another agent.
|
|
189
|
+
5. Use `bin/agent.sh ask` and `bin/agent.sh answer` for asynchronous questions.
|
|
190
|
+
6. Run `bin/agent.sh activity --for <person>` to see pending work.
|
|
191
|
+
7. Run `bin/agent.sh search "<query>"` to recall shared memory (decisions, handoffs, knowledge) before answering questions about past work.
|
|
192
|
+
8. Run `bin/agent.sh branch --topic "<what you are working on>"` before code changes when you need a task branch/worktree.
|
|
193
|
+
9. Run `bin/agent.sh save` and `bin/agent.sh wrap` for portable save/wrap flows.
|
|
194
|
+
|
|
195
|
+
This protocol is runtime-neutral. Claude Code may still use .claude hooks and
|
|
196
|
+
skills, while Codex or another agent can call this script directly.
|
|
197
|
+
EOF
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
cmd_people() {
|
|
201
|
+
ensure_memory
|
|
202
|
+
local people_dir="$MEMORY_DIR/people"
|
|
203
|
+
[ -d "$people_dir" ] || return 0
|
|
204
|
+
local f github display
|
|
205
|
+
for f in "$people_dir"/*.md; do
|
|
206
|
+
[ -f "$f" ] || continue
|
|
207
|
+
github="$(basename "$f" .md)"
|
|
208
|
+
display="$(sed -nE 's/^name:[[:space:]]*(.*)$/\1/p; s/^# (.*)$/\1/p' "$f" | head -1)"
|
|
209
|
+
[ -z "$display" ] && display="$github"
|
|
210
|
+
printf '%s\t%s\n' "$github" "$display"
|
|
211
|
+
done
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
cmd_sync() {
|
|
215
|
+
sync_memory
|
|
216
|
+
echo "synced: $MEMORY_DIR"
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
cmd_activity() {
|
|
220
|
+
ensure_memory
|
|
221
|
+
local for_person=""
|
|
222
|
+
local limit=12
|
|
223
|
+
while [ $# -gt 0 ]; do
|
|
224
|
+
case "$1" in
|
|
225
|
+
--for) for_person="${2:-}"; shift 2 ;;
|
|
226
|
+
--limit) limit="${2:-12}"; shift 2 ;;
|
|
227
|
+
*) die "unknown activity option: $1" ;;
|
|
228
|
+
esac
|
|
229
|
+
done
|
|
230
|
+
|
|
231
|
+
echo "Handoffs"
|
|
232
|
+
local index="$MEMORY_DIR/handoffs/index.md"
|
|
233
|
+
if [ -f "$index" ]; then
|
|
234
|
+
if [ -n "$for_person" ]; then
|
|
235
|
+
grep -i "handoff to ${for_person}" "$index" 2>/dev/null | head -n "$limit" || true
|
|
236
|
+
else
|
|
237
|
+
grep '^- ' "$index" 2>/dev/null | head -n "$limit" || true
|
|
238
|
+
fi
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
echo
|
|
242
|
+
echo "Questions"
|
|
243
|
+
local qdir="$MEMORY_DIR/knowledge/questions"
|
|
244
|
+
[ -d "$qdir" ] || return 0
|
|
245
|
+
local q from to topic status
|
|
246
|
+
while IFS= read -r q; do
|
|
247
|
+
from="$(sed -nE 's/^from:[[:space:]]*(.*)$/\1/p' "$q" | head -1)"
|
|
248
|
+
to="$(sed -nE 's/^to:[[:space:]]*(.*)$/\1/p' "$q" | head -1)"
|
|
249
|
+
topic="$(sed -nE 's/^topic:[[:space:]]*(.*)$/\1/p' "$q" | head -1)"
|
|
250
|
+
status="$(sed -nE 's/^status:[[:space:]]*(.*)$/\1/p' "$q" | head -1)"
|
|
251
|
+
[ -z "$status" ] && status="pending"
|
|
252
|
+
if [ -n "$for_person" ] && [ "$(echo "$to" | tr '[:upper:]' '[:lower:]')" != "$(echo "$for_person" | tr '[:upper:]' '[:lower:]')" ]; then
|
|
253
|
+
continue
|
|
254
|
+
fi
|
|
255
|
+
printf '%s\n' "- ${from} -> ${to} [${status}]: ${topic} (${q#$MEMORY_DIR/})"
|
|
256
|
+
done < <(find "$qdir" -type f -name '*.md' | sort -r | head -n "$limit")
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
cmd_branch() {
|
|
260
|
+
local topic="" author="" branch_type="" slug="" branch="" wt_path="" existing_wt="" base=""
|
|
261
|
+
|
|
262
|
+
while [ $# -gt 0 ]; do
|
|
263
|
+
case "$1" in
|
|
264
|
+
--topic|--description) topic="${2:-}"; shift 2 ;;
|
|
265
|
+
--from|--author) author="${2:-}"; shift 2 ;;
|
|
266
|
+
--type) branch_type="${2:-}"; shift 2 ;;
|
|
267
|
+
*) die "unknown branch option: $1" ;;
|
|
268
|
+
esac
|
|
269
|
+
done
|
|
270
|
+
|
|
271
|
+
[ -n "$topic" ] || topic="$(date +%Y-%m-%d)"
|
|
272
|
+
[ -n "$author" ] || author="$(current_author)"
|
|
273
|
+
|
|
274
|
+
if [ -z "$branch_type" ]; then
|
|
275
|
+
case "$(echo "$topic" | tr '[:upper:]' '[:lower:]')" in
|
|
276
|
+
*fix*|*bug*|*broken*|*crash*) branch_type="bugfix" ;;
|
|
277
|
+
*feature*|*add*|*implement*|*new*) branch_type="feature" ;;
|
|
278
|
+
*) branch_type="dev" ;;
|
|
279
|
+
esac
|
|
280
|
+
fi
|
|
281
|
+
case "$branch_type" in
|
|
282
|
+
dev|feature|bugfix) ;;
|
|
283
|
+
*) die "invalid --type: $branch_type (valid: dev|feature|bugfix)" ;;
|
|
284
|
+
esac
|
|
285
|
+
|
|
286
|
+
slug="$(slugify "$topic")"
|
|
287
|
+
[ -n "$slug" ] || slug="$(date +%Y-%m-%d)"
|
|
288
|
+
case "$branch_type" in
|
|
289
|
+
dev) branch="dev/${author}/${slug}" ;;
|
|
290
|
+
feature) branch="feature/${slug}" ;;
|
|
291
|
+
bugfix) branch="bugfix/${slug}" ;;
|
|
292
|
+
esac
|
|
293
|
+
|
|
294
|
+
base="$(base_ref)" || die "could not find a safe branch point"
|
|
295
|
+
|
|
296
|
+
if [ -f "$SCRIPT_DIR/.git" ]; then
|
|
297
|
+
if git -C "$SCRIPT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
|
|
298
|
+
git -C "$SCRIPT_DIR" checkout "$branch" --quiet
|
|
299
|
+
else
|
|
300
|
+
git -C "$SCRIPT_DIR" checkout -b "$branch" "$base" --quiet
|
|
301
|
+
fi
|
|
302
|
+
egregore_link_shared_state "$SCRIPT_DIR" "$MAIN_PROJECT_DIR" >/dev/null 2>/dev/null || true
|
|
303
|
+
echo "branch: $branch"
|
|
304
|
+
echo "worktree: $SCRIPT_DIR"
|
|
305
|
+
return 0
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
existing_wt="$(worktree_for_branch "$branch")"
|
|
309
|
+
if [ -n "$existing_wt" ] && [ -d "$existing_wt" ]; then
|
|
310
|
+
bash "$MAIN_PROJECT_DIR/bin/worktree.sh" setup "$existing_wt" "$MAIN_PROJECT_DIR" >/dev/null 2>/dev/null || true
|
|
311
|
+
echo "branch: $branch"
|
|
312
|
+
echo "worktree: $existing_wt"
|
|
313
|
+
return 0
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
if ! git -C "$MAIN_PROJECT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
|
|
317
|
+
git -C "$MAIN_PROJECT_DIR" branch "$branch" "$base" >/dev/null 2>&1 || die "failed to create branch $branch"
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
wt_path="$MAIN_PROJECT_DIR/.claude/worktrees/$slug"
|
|
321
|
+
if [ -e "$wt_path" ]; then
|
|
322
|
+
die "worktree path already exists: $wt_path"
|
|
323
|
+
fi
|
|
324
|
+
|
|
325
|
+
mkdir -p "$MAIN_PROJECT_DIR/.claude/worktrees"
|
|
326
|
+
git -C "$MAIN_PROJECT_DIR" worktree add "$wt_path" "$branch" --quiet 2>/dev/null || die "failed to create worktree at $wt_path"
|
|
327
|
+
bash "$MAIN_PROJECT_DIR/bin/worktree.sh" setup "$wt_path" "$MAIN_PROJECT_DIR" >/dev/null 2>/dev/null || true
|
|
328
|
+
|
|
329
|
+
echo "branch: $branch"
|
|
330
|
+
echo "worktree: $wt_path"
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
ensure_working_branch() {
|
|
334
|
+
local topic="${1:-$(date +%Y-%m-%d)}"
|
|
335
|
+
local author branch slug base
|
|
336
|
+
branch="$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || echo "")"
|
|
337
|
+
case "$branch" in
|
|
338
|
+
dev/*|feature/*|bugfix/*) echo "$branch"; return 0 ;;
|
|
339
|
+
esac
|
|
340
|
+
|
|
341
|
+
author="$(current_author)"
|
|
342
|
+
slug="$(slugify "$topic")"
|
|
343
|
+
[ -n "$slug" ] || slug="$(date +%Y-%m-%d)"
|
|
344
|
+
branch="dev/${author}/${slug}"
|
|
345
|
+
base="$(base_ref)" || die "could not find a safe branch point"
|
|
346
|
+
|
|
347
|
+
if git -C "$SCRIPT_DIR" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
|
|
348
|
+
git -C "$SCRIPT_DIR" checkout "$branch" --quiet || die "failed to checkout $branch"
|
|
349
|
+
else
|
|
350
|
+
git -C "$SCRIPT_DIR" checkout -b "$branch" "$base" --quiet || die "failed to create $branch"
|
|
351
|
+
fi
|
|
352
|
+
echo "$branch"
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
build_pr_body() {
|
|
356
|
+
# Compliant fallback PR body (spec: .claude/context/pr-format.md) built
|
|
357
|
+
# from the commit log + diff when the calling agent supplies none.
|
|
358
|
+
local topic="${1:-portable save}" base commits stat
|
|
359
|
+
base="$(resolve_base_branch)" || return 1
|
|
360
|
+
commits="$(git -C "$SCRIPT_DIR" log --pretty='- %s' "origin/$base..HEAD" 2>/dev/null | head -8)"
|
|
361
|
+
[ -n "$commits" ] || commits="- (commit list unavailable — see the Files tab)"
|
|
362
|
+
stat="$(git -C "$SCRIPT_DIR" diff --shortstat "origin/$base...HEAD" 2>/dev/null | sed 's/^ *//')"
|
|
363
|
+
printf '## What\n%s\n\n## Why\nShell-agent session save — topic: %s. Body auto-generated by bin/agent.sh; pass --pr-body for a hand-written description.\n\n## Verification\nNot verified — auto-generated skeleton; review the diff before merging.%s\n\n🤖 Saved via bin/agent.sh\n' \
|
|
364
|
+
"$commits" "$topic" "${stat:+ ($stat)}"
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
cmd_save() {
|
|
368
|
+
local message="" topic="" no_pr=0 branch base pushed="false" committed="false" pr_url="" existing_pr="" pr_number="" non_md="" merged="false" pr_body="" pr_body_file=""
|
|
369
|
+
|
|
370
|
+
while [ $# -gt 0 ]; do
|
|
371
|
+
case "$1" in
|
|
372
|
+
--message|-m) message="${2:-}"; shift 2 ;;
|
|
373
|
+
--topic) topic="${2:-}"; shift 2 ;;
|
|
374
|
+
--pr-body) pr_body="${2:-}"; shift 2 ;;
|
|
375
|
+
--pr-body-file) pr_body_file="${2:-}"; shift 2 ;;
|
|
376
|
+
--no-pr) no_pr=1; shift ;;
|
|
377
|
+
*) die "unknown save option: $1" ;;
|
|
378
|
+
esac
|
|
379
|
+
done
|
|
380
|
+
|
|
381
|
+
[ -n "$topic" ] || topic="portable save"
|
|
382
|
+
[ -n "$message" ] || message="Save: $topic"
|
|
383
|
+
base="$(resolve_base_branch)" || die "save stopped before Git changes"
|
|
384
|
+
|
|
385
|
+
if [ -d "$MEMORY_DIR" ]; then
|
|
386
|
+
save_memory "$message" "."
|
|
387
|
+
echo "memory: synced"
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
branch="$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || echo "")"
|
|
391
|
+
if [ -n "$(git -C "$SCRIPT_DIR" status --porcelain 2>/dev/null | head -1)" ]; then
|
|
392
|
+
branch="$(ensure_working_branch "$topic")"
|
|
393
|
+
git -C "$SCRIPT_DIR" add -A >/dev/null 2>&1 || die "git add failed"
|
|
394
|
+
if ! git -C "$SCRIPT_DIR" diff --cached --quiet 2>/dev/null; then
|
|
395
|
+
git -C "$SCRIPT_DIR" commit -m "$message" --quiet || die "git commit failed"
|
|
396
|
+
committed="true"
|
|
397
|
+
fi
|
|
398
|
+
fi
|
|
399
|
+
[ -n "$branch" ] || branch="$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || echo "")"
|
|
400
|
+
|
|
401
|
+
if [ -n "$branch" ] && git -C "$SCRIPT_DIR" remote get-url origin >/dev/null 2>&1; then
|
|
402
|
+
if git -C "$SCRIPT_DIR" push -u origin "$branch" --quiet 2>/dev/null; then
|
|
403
|
+
pushed="true"
|
|
404
|
+
else
|
|
405
|
+
die "push failed for $branch; commits are safe locally"
|
|
406
|
+
fi
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
if [ "$no_pr" = "0" ] && [ "$pushed" = "true" ] && command -v gh >/dev/null 2>&1; then
|
|
410
|
+
existing_pr="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url // empty' 2>/dev/null || true)"
|
|
411
|
+
if [ -n "$existing_pr" ]; then
|
|
412
|
+
pr_url="$existing_pr"
|
|
413
|
+
else
|
|
414
|
+
if [ -z "$pr_body" ] && [ -n "$pr_body_file" ] && [ -f "$pr_body_file" ]; then
|
|
415
|
+
pr_body="$(cat "$pr_body_file")"
|
|
416
|
+
fi
|
|
417
|
+
[ -n "$pr_body" ] || pr_body="$(build_pr_body "$topic")"
|
|
418
|
+
pr_url="$(gh pr create --base "$base" --head "$branch" --title "$message" --body "$pr_body" 2>/dev/null || true)"
|
|
419
|
+
fi
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
# Non-coding saves auto-merge to the configured base (same rule as /save and the
|
|
423
|
+
# handoff helper; policy in bin/lib/noncode.sh). `--auto` needs repo
|
|
424
|
+
# auto-merge + pending required checks; without branch protection it always
|
|
425
|
+
# errors, so fall back to a direct merge.
|
|
426
|
+
if [ -n "$pr_url" ]; then
|
|
427
|
+
# shellcheck source=bin/lib/noncode.sh
|
|
428
|
+
. "$SCRIPT_DIR/bin/lib/noncode.sh" 2>/dev/null || true
|
|
429
|
+
type noncode_blockers >/dev/null 2>&1 || noncode_blockers() {
|
|
430
|
+
git -C "${2:-.}" diff "${1:-origin/$base}...HEAD" --name-only 2>/dev/null | grep -v '\.md$' | head -1 || true
|
|
431
|
+
}
|
|
432
|
+
pr_number="${pr_url##*/}"
|
|
433
|
+
non_code="$(noncode_blockers "origin/$base" "$SCRIPT_DIR")"
|
|
434
|
+
if [ -z "$non_code" ] && [ -n "$pr_number" ]; then
|
|
435
|
+
if gh pr merge "$pr_number" --auto --merge >/dev/null 2>&1 \
|
|
436
|
+
|| gh pr merge "$pr_number" --merge >/dev/null 2>&1; then
|
|
437
|
+
merged="true"
|
|
438
|
+
fi
|
|
439
|
+
fi
|
|
440
|
+
fi
|
|
441
|
+
|
|
442
|
+
echo "branch: ${branch:-none}"
|
|
443
|
+
echo "commit: $committed"
|
|
444
|
+
echo "push: $pushed"
|
|
445
|
+
[ -n "$pr_url" ] && echo "pr: $pr_url"
|
|
446
|
+
[ "$merged" = "true" ] && echo "merge: non-coding, merged to $base"
|
|
447
|
+
return 0
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
cmd_wrap() {
|
|
451
|
+
ensure_memory
|
|
452
|
+
local from="" topic="" summary="" body="" body_file="" no_push=0
|
|
453
|
+
|
|
454
|
+
while [ $# -gt 0 ]; do
|
|
455
|
+
case "$1" in
|
|
456
|
+
--from) from="${2:-}"; shift 2 ;;
|
|
457
|
+
--topic) topic="${2:-}"; shift 2 ;;
|
|
458
|
+
--summary) summary="${2:-}"; shift 2 ;;
|
|
459
|
+
--body) body="${2:-}"; shift 2 ;;
|
|
460
|
+
--body-file) body_file="${2:-}"; shift 2 ;;
|
|
461
|
+
--no-push) no_push=1; shift ;;
|
|
462
|
+
*) die "unknown wrap option: $1" ;;
|
|
463
|
+
esac
|
|
464
|
+
done
|
|
465
|
+
|
|
466
|
+
[ -n "$from" ] || from="$(current_author)"
|
|
467
|
+
[ -n "$topic" ] || die "wrap requires --topic"
|
|
468
|
+
[ -n "$summary" ] || die "wrap requires --summary"
|
|
469
|
+
if [ -n "$body_file" ]; then
|
|
470
|
+
[ -f "$body_file" ] || die "body file not found: $body_file"
|
|
471
|
+
body="$(cat "$body_file")"
|
|
472
|
+
elif [ -z "$body" ] && [ ! -t 0 ]; then
|
|
473
|
+
body="$(cat)"
|
|
474
|
+
fi
|
|
475
|
+
[ -n "$body" ] || body="$summary"
|
|
476
|
+
|
|
477
|
+
local tmpd result rel session_id branch
|
|
478
|
+
local capture_args=(--mode personal)
|
|
479
|
+
tmpd="$(mktemp -d -t egregore-agent-wrap-XXXXXX)"
|
|
480
|
+
trap 'rm -rf "$tmpd"' RETURN
|
|
481
|
+
session_id="$(cat "$SCRIPT_DIR/.egregore-session-id" 2>/dev/null || true)"
|
|
482
|
+
branch="$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || true)"
|
|
483
|
+
[ "$no_push" = "1" ] && capture_args+=(--no-push)
|
|
484
|
+
|
|
485
|
+
printf '%s\n' "$body" |
|
|
486
|
+
TMPDIR="$tmpd" bash "$SCRIPT_DIR/bin/capture-run.sh" \
|
|
487
|
+
"${capture_args[@]}" \
|
|
488
|
+
--author "$from" \
|
|
489
|
+
--topic "$topic" \
|
|
490
|
+
--summary "$summary" \
|
|
491
|
+
--session-id "$session_id" \
|
|
492
|
+
--branch "$branch" >/dev/null
|
|
493
|
+
|
|
494
|
+
result="$tmpd/capture-run-result.json"
|
|
495
|
+
rel="$(jq -r '.file // empty' "$result" 2>/dev/null || true)"
|
|
496
|
+
[ -n "$rel" ] || die "wrap was not created"
|
|
497
|
+
echo "wrap: memory/$rel"
|
|
498
|
+
|
|
499
|
+
# Session close: non-coding core-repo changes save + merge themselves
|
|
500
|
+
# (gated inside session-autosave.sh — code is never auto-committed).
|
|
501
|
+
if [ "$no_push" = "0" ]; then
|
|
502
|
+
( bash "$SCRIPT_DIR/bin/session-autosave.sh" --dir "$SCRIPT_DIR" >/dev/null 2>&1 & ) >/dev/null 2>&1
|
|
503
|
+
fi
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
cmd_handoff() {
|
|
507
|
+
ensure_memory
|
|
508
|
+
local from="" to="" topic="" body="" body_file="" project="" intent="action"
|
|
509
|
+
local no_publish=0 no_notify=0 json=0 body_supplied=0 content_mode="generated"
|
|
510
|
+
NO_PUSH=0
|
|
511
|
+
|
|
512
|
+
while [ $# -gt 0 ]; do
|
|
513
|
+
case "$1" in
|
|
514
|
+
--from) from="${2:-}"; shift 2 ;;
|
|
515
|
+
--to) to="${2:-}"; shift 2 ;;
|
|
516
|
+
--topic) topic="${2:-}"; shift 2 ;;
|
|
517
|
+
--body) body="${2:-}"; shift 2 ;;
|
|
518
|
+
--body-file) body_file="${2:-}"; shift 2 ;;
|
|
519
|
+
--project) project="${2:-}"; shift 2 ;;
|
|
520
|
+
--intent) intent="${2:-}"; shift 2 ;;
|
|
521
|
+
--no-push) NO_PUSH=1; shift ;;
|
|
522
|
+
--no-publish) no_publish=1; shift ;;
|
|
523
|
+
--no-notify) no_notify=1; shift ;;
|
|
524
|
+
--json) json=1; shift ;;
|
|
525
|
+
*) die "unknown handoff option: $1" ;;
|
|
526
|
+
esac
|
|
527
|
+
done
|
|
528
|
+
|
|
529
|
+
[ -z "$from" ] && from="$(person_from_state)"
|
|
530
|
+
[ -n "$from" ] || die "handoff requires --from"
|
|
531
|
+
[ -n "$topic" ] || die "handoff requires --topic"
|
|
532
|
+
case "$intent" in
|
|
533
|
+
action|feedback|fyi) ;;
|
|
534
|
+
*) die "invalid --intent: $intent (action|feedback|fyi)" ;;
|
|
535
|
+
esac
|
|
536
|
+
if [ -n "$body_file" ]; then
|
|
537
|
+
[ -f "$body_file" ] || die "body file not found: $body_file"
|
|
538
|
+
body="$(cat "$body_file")"
|
|
539
|
+
body_supplied=1
|
|
540
|
+
elif [ -z "$body" ] && [ ! -t 0 ]; then
|
|
541
|
+
body="$(cat)"
|
|
542
|
+
[ -n "$body" ] && body_supplied=1
|
|
543
|
+
elif [ -n "$body" ]; then
|
|
544
|
+
body_supplied=1
|
|
545
|
+
fi
|
|
546
|
+
[ "$body_supplied" = "1" ] && content_mode="supplied"
|
|
547
|
+
|
|
548
|
+
local today tmpd result result_out rel stdout_file
|
|
549
|
+
local handoff_args=()
|
|
550
|
+
today="$(date +%Y-%m-%d)"
|
|
551
|
+
tmpd="$(mktemp -d -t egregore-agent-handoff-XXXXXX)"
|
|
552
|
+
trap 'rm -rf "$tmpd"' RETURN
|
|
553
|
+
result_out="$(mktemp -t egregore-agent-handoff-result-XXXXXX.json)"
|
|
554
|
+
stdout_file="$tmpd/stdout"
|
|
555
|
+
|
|
556
|
+
[ -n "$to" ] && handoff_args+=(--recipient "$to")
|
|
557
|
+
[ -n "$project" ] && handoff_args+=(--project "$project")
|
|
558
|
+
handoff_args+=(--intent "$intent" --content-mode "$content_mode")
|
|
559
|
+
[ "$content_mode" = "generated" ] && handoff_args+=(--include-session-artifacts)
|
|
560
|
+
[ "$NO_PUSH" = "1" ] && handoff_args+=(--no-push)
|
|
561
|
+
[ "$no_publish" = "1" ] && handoff_args+=(--no-publish)
|
|
562
|
+
[ "$no_notify" = "1" ] && handoff_args+=(--no-notify)
|
|
563
|
+
|
|
564
|
+
{
|
|
565
|
+
printf '%s\n' '---'
|
|
566
|
+
printf 'capture_schema: egregore-capture/v1\n'
|
|
567
|
+
printf 'capture_mode: addressed\n'
|
|
568
|
+
printf 'kind: addressed\n'
|
|
569
|
+
printf 'content_mode: %s\n' "$content_mode"
|
|
570
|
+
printf 'from: %s\n' "$(yaml_str "$from")"
|
|
571
|
+
[ -n "$to" ] && printf 'addressed_to: %s\n' "$(yaml_str "$to")"
|
|
572
|
+
printf 'date: %s\n' "$today"
|
|
573
|
+
printf 'topic: %s\n' "$(yaml_str "$topic")"
|
|
574
|
+
printf 'intent: %s\n' "$intent"
|
|
575
|
+
[ -n "$project" ] && printf 'project: %s\n' "$(yaml_str "$project")"
|
|
576
|
+
printf '%s\n\n' '---'
|
|
577
|
+
if [ "$content_mode" = "supplied" ]; then
|
|
578
|
+
printf '%s\n' "$body"
|
|
579
|
+
else
|
|
580
|
+
printf '# Handoff: %s\n\n' "$topic"
|
|
581
|
+
printf '## Briefing\n\nNo briefing was supplied.\n\n'
|
|
582
|
+
printf '## Next Steps\n\n1. Continue from this handoff using the shared Egregore memory protocol.\n'
|
|
583
|
+
fi
|
|
584
|
+
} | TMPDIR="$tmpd" bash "$SCRIPT_DIR/bin/capture-run.sh" \
|
|
585
|
+
--mode addressed \
|
|
586
|
+
--author "$from" \
|
|
587
|
+
--topic "$topic" \
|
|
588
|
+
"${handoff_args[@]}" \
|
|
589
|
+
> "$stdout_file"
|
|
590
|
+
|
|
591
|
+
result="$tmpd/handoff-run-result.json"
|
|
592
|
+
rel="$(jq -r '.file // empty' "$result" 2>/dev/null || true)"
|
|
593
|
+
[ -n "$rel" ] || die "handoff was not created"
|
|
594
|
+
cp "$result" "$result_out"
|
|
595
|
+
if [ "$json" = "1" ]; then
|
|
596
|
+
cat "$result_out"
|
|
597
|
+
return 0
|
|
598
|
+
fi
|
|
599
|
+
[ -s "$stdout_file" ] && sed 's/^/status: /' "$stdout_file"
|
|
600
|
+
echo "handoff: memory/$rel"
|
|
601
|
+
echo "result: $result_out"
|
|
602
|
+
|
|
603
|
+
# Parity with the Claude /handoff skill: save core-repo session work in the
|
|
604
|
+
# background (non-coding diffs auto-merge to the configured base; code stays
|
|
605
|
+
# in a PR).
|
|
606
|
+
if [ "$NO_PUSH" = "0" ]; then
|
|
607
|
+
( bash "$SCRIPT_DIR/bin/handoff-save-egregore.sh" "$from" "$topic" --repo-dir "$SCRIPT_DIR" >/dev/null 2>&1 & ) >/dev/null 2>&1
|
|
608
|
+
fi
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
cmd_ask() {
|
|
612
|
+
ensure_memory
|
|
613
|
+
local from="" to="" topic="" question=""
|
|
614
|
+
local harvest_id="" harvest_session_id="" turn="" question_intent="" context_mode=""
|
|
615
|
+
NO_PUSH=0
|
|
616
|
+
|
|
617
|
+
while [ $# -gt 0 ]; do
|
|
618
|
+
case "$1" in
|
|
619
|
+
--from) from="${2:-}"; shift 2 ;;
|
|
620
|
+
--to) to="${2:-}"; shift 2 ;;
|
|
621
|
+
--topic) topic="${2:-}"; shift 2 ;;
|
|
622
|
+
--question) question="${2:-}"; shift 2 ;;
|
|
623
|
+
--harvest-id) harvest_id="${2:-}"; shift 2 ;;
|
|
624
|
+
--harvest-session-id) harvest_session_id="${2:-}"; shift 2 ;;
|
|
625
|
+
--turn) turn="${2:-}"; shift 2 ;;
|
|
626
|
+
--question-intent) question_intent="${2:-}"; shift 2 ;;
|
|
627
|
+
--context-mode) context_mode="${2:-}"; shift 2 ;;
|
|
628
|
+
--no-push) NO_PUSH=1; shift ;;
|
|
629
|
+
*) die "unknown ask option: $1" ;;
|
|
630
|
+
esac
|
|
631
|
+
done
|
|
632
|
+
|
|
633
|
+
[ -z "$from" ] && from="$(person_from_state)"
|
|
634
|
+
[ -n "$from" ] || die "ask requires --from"
|
|
635
|
+
[ -n "$to" ] || die "ask requires --to"
|
|
636
|
+
[ -n "$topic" ] || die "ask requires --topic"
|
|
637
|
+
[ -n "$question" ] || die "ask requires --question"
|
|
638
|
+
|
|
639
|
+
if [ -n "$context_mode" ]; then
|
|
640
|
+
case "$context_mode" in
|
|
641
|
+
blind|disclosed|comparative) ;;
|
|
642
|
+
*) die "invalid --context-mode: $context_mode (valid: blind|disclosed|comparative)" ;;
|
|
643
|
+
esac
|
|
644
|
+
fi
|
|
645
|
+
|
|
646
|
+
if [ -n "$turn" ]; then
|
|
647
|
+
case "$turn" in
|
|
648
|
+
''|*[!0-9]*) die "invalid --turn: must be a non-negative integer" ;;
|
|
649
|
+
esac
|
|
650
|
+
fi
|
|
651
|
+
|
|
652
|
+
reject_newlines "--from" "$from"
|
|
653
|
+
reject_newlines "--to" "$to"
|
|
654
|
+
reject_newlines "--topic" "$topic"
|
|
655
|
+
reject_newlines "--question" "$question"
|
|
656
|
+
reject_newlines "--harvest-id" "$harvest_id"
|
|
657
|
+
reject_newlines "--harvest-session-id" "$harvest_session_id"
|
|
658
|
+
reject_newlines "--question-intent" "$question_intent"
|
|
659
|
+
|
|
660
|
+
local now slug rel abs n
|
|
661
|
+
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
662
|
+
slug="$(slugify "$topic")"
|
|
663
|
+
mkdir -p "$MEMORY_DIR/knowledge/questions"
|
|
664
|
+
rel="knowledge/questions/$(date +%Y-%m-%d)-${from}-to-${to}-${slug}.md"
|
|
665
|
+
abs="$MEMORY_DIR/$rel"
|
|
666
|
+
n=2
|
|
667
|
+
while [ -e "$abs" ]; do
|
|
668
|
+
rel="knowledge/questions/$(date +%Y-%m-%d)-${from}-to-${to}-${slug}-${n}.md"
|
|
669
|
+
abs="$MEMORY_DIR/$rel"
|
|
670
|
+
n=$((n + 1))
|
|
671
|
+
done
|
|
672
|
+
|
|
673
|
+
{
|
|
674
|
+
echo "---"
|
|
675
|
+
echo "from: $from"
|
|
676
|
+
echo "to: $to"
|
|
677
|
+
echo "topic: $topic"
|
|
678
|
+
echo "status: pending"
|
|
679
|
+
echo "created: $now"
|
|
680
|
+
[ -n "$harvest_id" ] && echo "harvest_id: $(yaml_str "$harvest_id")"
|
|
681
|
+
[ -n "$harvest_session_id" ] && echo "harvest_session_id: $(yaml_str "$harvest_session_id")"
|
|
682
|
+
[ -n "$turn" ] && echo "turn: $turn"
|
|
683
|
+
[ -n "$question_intent" ] && echo "question_intent: $(yaml_str "$question_intent")"
|
|
684
|
+
[ -n "$context_mode" ] && echo "context_mode: $context_mode"
|
|
685
|
+
echo "---"
|
|
686
|
+
echo ""
|
|
687
|
+
echo "## Questions"
|
|
688
|
+
echo ""
|
|
689
|
+
echo "- $question"
|
|
690
|
+
} > "$abs"
|
|
691
|
+
|
|
692
|
+
save_memory "Question: ${topic} (to ${to})" "$rel"
|
|
693
|
+
echo "question: memory/$rel"
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
cmd_answer() {
|
|
697
|
+
ensure_memory
|
|
698
|
+
local from="" question_path="" body=""
|
|
699
|
+
NO_PUSH=0
|
|
700
|
+
|
|
701
|
+
while [ $# -gt 0 ]; do
|
|
702
|
+
case "$1" in
|
|
703
|
+
--from) from="${2:-}"; shift 2 ;;
|
|
704
|
+
--question) question_path="${2:-}"; shift 2 ;;
|
|
705
|
+
--body) body="${2:-}"; shift 2 ;;
|
|
706
|
+
--no-push) NO_PUSH=1; shift ;;
|
|
707
|
+
*) die "unknown answer option: $1" ;;
|
|
708
|
+
esac
|
|
709
|
+
done
|
|
710
|
+
|
|
711
|
+
[ -z "$from" ] && from="$(person_from_state)"
|
|
712
|
+
[ -n "$from" ] || die "answer requires --from"
|
|
713
|
+
[ -n "$question_path" ] || die "answer requires --question"
|
|
714
|
+
[ -n "$body" ] || die "answer requires --body"
|
|
715
|
+
|
|
716
|
+
local abs rel now tmp
|
|
717
|
+
case "$question_path" in
|
|
718
|
+
"$MEMORY_DIR"/*) abs="$question_path" ;;
|
|
719
|
+
memory/*) abs="$MEMORY_DIR/${question_path#memory/}" ;;
|
|
720
|
+
*) abs="$MEMORY_DIR/$question_path" ;;
|
|
721
|
+
esac
|
|
722
|
+
[ -f "$abs" ] || die "question file not found: $question_path"
|
|
723
|
+
rel="${abs#$MEMORY_DIR/}"
|
|
724
|
+
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
725
|
+
tmp="$abs.tmp.$$"
|
|
726
|
+
|
|
727
|
+
awk -v from="$from" -v now="$now" '
|
|
728
|
+
BEGIN { in_fm = 0; added = 0; saw_status = 0 }
|
|
729
|
+
NR == 1 && $0 == "---" { in_fm = 1; print; next }
|
|
730
|
+
in_fm && /^status:/ { print "status: answered"; saw_status = 1; next }
|
|
731
|
+
in_fm && $0 == "---" {
|
|
732
|
+
if (!saw_status) print "status: answered"
|
|
733
|
+
if (!added) {
|
|
734
|
+
print "answered_by: " from
|
|
735
|
+
print "answered_at: " now
|
|
736
|
+
added = 1
|
|
737
|
+
}
|
|
738
|
+
in_fm = 0
|
|
739
|
+
print
|
|
740
|
+
next
|
|
741
|
+
}
|
|
742
|
+
{ print }
|
|
743
|
+
' "$abs" > "$tmp" && mv "$tmp" "$abs"
|
|
744
|
+
|
|
745
|
+
{
|
|
746
|
+
printf '\n## Answer\n\n'
|
|
747
|
+
printf '**From**: %s\n' "$from"
|
|
748
|
+
printf '**At**: %s\n\n' "$now"
|
|
749
|
+
printf '%s\n' "$body"
|
|
750
|
+
} >> "$abs"
|
|
751
|
+
|
|
752
|
+
save_memory "Answer question: ${rel}" "$rel"
|
|
753
|
+
echo "answered: memory/$rel"
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
cmd_search() {
|
|
757
|
+
bash "$SCRIPT_DIR/bin/search.sh" query "$@"
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
case "${1:-}" in
|
|
761
|
+
--help|-h|help|"") usage ;;
|
|
762
|
+
protocol) shift; cmd_protocol "$@" ;;
|
|
763
|
+
sync) shift; cmd_sync "$@" ;;
|
|
764
|
+
activity) shift; cmd_activity "$@" ;;
|
|
765
|
+
search) shift; cmd_search "$@" ;;
|
|
766
|
+
people) shift; cmd_people "$@" ;;
|
|
767
|
+
branch) shift; cmd_branch "$@" ;;
|
|
768
|
+
save) shift; cmd_save "$@" ;;
|
|
769
|
+
autosave) shift; bash "$SCRIPT_DIR/bin/autosave.sh" "$@" ;;
|
|
770
|
+
wrap) shift; cmd_wrap "$@" ;;
|
|
771
|
+
handoff) shift; cmd_handoff "$@" ;;
|
|
772
|
+
ask) shift; cmd_ask "$@" ;;
|
|
773
|
+
answer) shift; cmd_answer "$@" ;;
|
|
774
|
+
*) die "unknown command: $1" ;;
|
|
775
|
+
esac
|