0786286cde
capture-note.sh reads an optional leading bug:/feature:/chore:/idea: keyword as the inbox type (default idea, always P2). AGENTS.md: capture mode marked live; two durable lessons — the Update button deploys origin/master so commits must land there, and Element intercepts /capture (the thread is the trigger).
65 lines
2.6 KiB
Bash
Executable File
65 lines
2.6 KiB
Bash
Executable File
#!/bin/zsh -l
|
|
# capture-note.sh — matrix-bridge capture wrapper.
|
|
#
|
|
# Invoked over SSH by the bot: capture-note.sh <project> <text...>
|
|
# Appends ONE line to the cross-project inbox (standards/INBOX.md) in the exact format the
|
|
# /capture skill uses, commits it, and best-effort pushes — so /triage (run later inside the
|
|
# target repo) drains it like any other captured item.
|
|
#
|
|
# Deterministic on purpose: no LLM, no token, nothing leaves the Mac except the git push to
|
|
# Gitea. The "smarts" (priority, repo-routing, phrasing) stay at /triage, where the human is —
|
|
# routing message text through a frontier model would break the sovereignty boundary (D13/D8).
|
|
# Type comes from an optional leading keyword the user types ("bug: ...", "feature: ...");
|
|
# anything without one defaults to a raw [idea]. Priority is always P2; /triage sets the real one.
|
|
#
|
|
# Why a login shell (-l): git config / PATH live in ~/.zprofile, which a non-login SSH shell
|
|
# skips — the same seam as launch-claude.sh / ask-claude.sh.
|
|
|
|
set -e
|
|
setopt extended_glob # for whitespace-run trimming below
|
|
|
|
standards="$HOME/Projects/standards"
|
|
inbox="$standards/INBOX.md"
|
|
|
|
project="$1"
|
|
shift || true
|
|
note="$*"
|
|
|
|
if [[ -z "$project" || -z "$note" ]]; then
|
|
print -u2 "usage: capture-note.sh <project> <text>"
|
|
exit 2
|
|
fi
|
|
if [[ ! -f "$inbox" ]]; then
|
|
print -u2 "capture-note: inbox not found: $inbox"
|
|
exit 1
|
|
fi
|
|
|
|
# Optional leading type keyword ("bug: ...", "feature: ...", etc.) → that type; default idea.
|
|
# Only fires when the text before the first colon is exactly one known keyword, so a note that
|
|
# merely contains a colon ("ratio is 3:1") is left untouched. Types: standards/guides/capture.md.
|
|
type="idea"
|
|
if [[ "$note" == *:* ]]; then
|
|
cand="${(L)note%%:*}" # lowercase the text before the first colon
|
|
cand="${cand##[[:space:]]#}" # trim surrounding whitespace
|
|
cand="${cand%%[[:space:]]#}"
|
|
case "$cand" in
|
|
bug|feature|idea|chore|skill|agent|project)
|
|
type="$cand"
|
|
note="${note#*:}" # drop "keyword:"
|
|
note="${note##[[:space:]]#}" # trim leading whitespace
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
line="- [ ] ($project) [$type][P2] $note — via matrix, $(date +%F)"
|
|
|
|
print -r -- "$line" >> "$inbox"
|
|
|
|
git -C "$standards" add INBOX.md
|
|
git -C "$standards" commit -q -m "Capture: ${note[1,60]} (via matrix)" -- INBOX.md
|
|
# Push is best-effort — a captured line committed locally is not lost if Gitea is unreachable.
|
|
git -C "$standards" push -q 2>/dev/null || print -u2 "capture-note: push skipped/failed (committed locally)"
|
|
|
|
# Echo the exact line so the bot can post it back into the thread as confirmation.
|
|
print -r -- "$line"
|