-
Notifications
You must be signed in to change notification settings - Fork 0
fix(okf): fix hook stdin, locking, prompt ordering #894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fadcd32
4a59b92
d8420e2
23c7d90
b712e09
ea166b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||
| # SessionEnd / PreCompact hook: periodically distill memsearch journals into the ~/wiki OKF bundle. | ||||||||||||||||||||||
| # Independent of the memsearch plugin's own SessionEnd hook — reads its journal output | ||||||||||||||||||||||
| # SessionEnd hook: periodically distill memsearch memories into the ~/wiki OKF bundle. | ||||||||||||||||||||||
| # Independent of the memsearch plugin's own SessionEnd hook — reads its memory output | ||||||||||||||||||||||
| # as a data source only, no changes to memsearch itself. | ||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
@@ -14,17 +14,18 @@ JOURNAL_DIR="${MEMSEARCH_DIR}/memory" | |||||||||||||||||||||
| WIKI_DIR="${OKF_WIKI_DIR:-${HOME}/wiki}" | ||||||||||||||||||||||
| STATE_FILE="${WIKI_DIR}/.okf-wiki-last-run" | ||||||||||||||||||||||
| LOCK_FILE="${WIKI_DIR}/.okf-wiki-maintenance.lock" | ||||||||||||||||||||||
| PROMPT_FILE="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/prompts/okf-wiki-review.txt" | ||||||||||||||||||||||
| PROMPT_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/okf-wiki-review.txt" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| [ -d "${JOURNAL_DIR}" ] || exit 0 | ||||||||||||||||||||||
| [ -f "${PROMPT_FILE}" ] || exit 0 | ||||||||||||||||||||||
| mkdir -p "${WIKI_DIR}" | ||||||||||||||||||||||
| command -v claude &>/dev/null || exit 0 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Acquire exclusive lock — prevents concurrent SessionEnd + PreCompact runs. | ||||||||||||||||||||||
| # fd 9 is opened on LOCK_FILE; flock holds it for this process's lifetime. | ||||||||||||||||||||||
| exec 9>"${LOCK_FILE}" | ||||||||||||||||||||||
| flock -n 9 || exit 0 # -n = non-blocking: exit immediately if already locked | ||||||||||||||||||||||
| # Acquire exclusive lock via atomic mkdir — POSIX portable, no flock/shlock needed. | ||||||||||||||||||||||
| if ! mkdir "${LOCK_FILE}" 2>/dev/null; then | ||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||
| fi | ||||||||||||||||||||||
| trap 'rmdir "${LOCK_FILE}"' EXIT | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Skip if already ran today (same calendar date). | ||||||||||||||||||||||
| if [ -f "${STATE_FILE}" ]; then | ||||||||||||||||||||||
|
|
@@ -35,43 +36,39 @@ if [ -f "${STATE_FILE}" ]; then | |||||||||||||||||||||
| fi | ||||||||||||||||||||||
| fi | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Only look at journals touched since the last run (falls back to last 3 days on first run). | ||||||||||||||||||||||
| # Memories since last run, or last 3 days on first run. Always include yesterday (-mtime -1 = <24h). | ||||||||||||||||||||||
| if [ -f "${STATE_FILE}" ]; then | ||||||||||||||||||||||
| recent_journals="$(find "${JOURNAL_DIR}" -maxdepth 1 -name '*.md' -newer "${STATE_FILE}" 2>/dev/null)" | ||||||||||||||||||||||
| recent_memories="$(find "${JOURNAL_DIR}" -maxdepth 1 -name '*.md' \( -newer "${STATE_FILE}" -o -mtime -1 \) 2>/dev/null)" | ||||||||||||||||||||||
| else | ||||||||||||||||||||||
| recent_journals="$(find "${JOURNAL_DIR}" -maxdepth 1 -name '*.md' -mtime -3 2>/dev/null)" | ||||||||||||||||||||||
| recent_memories="$(find "${JOURNAL_DIR}" -maxdepth 1 -name '*.md' -mtime -3 2>/dev/null)" | ||||||||||||||||||||||
| fi | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| [ -n "${recent_journals}" ] || exit 0 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Include memsearch-synthesized summaries if present (higher-signal than raw journals). | ||||||||||||||||||||||
| extra_context="" | ||||||||||||||||||||||
| [ -f "${MEMSEARCH_DIR}/PROJECT.md" ] && extra_context="${extra_context} | ||||||||||||||||||||||
| Project summary: ${MEMSEARCH_DIR}/PROJECT.md" | ||||||||||||||||||||||
| [ -f "${MEMSEARCH_DIR}/USER.md" ] && extra_context="${extra_context} | ||||||||||||||||||||||
| User profile: ${MEMSEARCH_DIR}/USER.md" | ||||||||||||||||||||||
| [ -n "${recent_memories}" ] || exit 0 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export MEMSEARCH_DISABLE=1 | ||||||||||||||||||||||
| export MEMSEARCH_NO_WATCH=1 | ||||||||||||||||||||||
| export OKF_WIKI_DISABLE=1 | ||||||||||||||||||||||
| unset CLAUDECODE # clear CLAUDECODE so the child session doesn't inherit hook context | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # hook runs with async:true — Claude Code does not block on this script. | ||||||||||||||||||||||
| # Run claude -p synchronously so flock holds for the full duration, preventing | ||||||||||||||||||||||
| # a concurrent PreCompact trigger from starting a second run. | ||||||||||||||||||||||
| # Run claude -p synchronously so mkdir lock holds for the full duration, | ||||||||||||||||||||||
| # preventing a concurrent trigger from starting a second run. | ||||||||||||||||||||||
| # Write state file only on success so a failed run does not suppress the next. | ||||||||||||||||||||||
|
Comment on lines
53
to
56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Stale "shlock" reference — the lock is now mkdir-based. This comment (line 54) still refers to "shlock," but the actual lock implemented at line 24-28 is an atomic 📝 Proposed fix-# Run claude -p synchronously so shlock holds for the full duration, preventing
+# Run claude -p synchronously so the mkdir lock holds for the full duration, preventing
# a concurrent trigger from starting a second run.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| if claude -p \ | ||||||||||||||||||||||
| prompt="$( | ||||||||||||||||||||||
| printf 'Wiki directory: %s\n' "${WIKI_DIR}" | ||||||||||||||||||||||
| [ -f "${MEMSEARCH_DIR}/USER.md" ] && printf 'User profile: %s\n' "${MEMSEARCH_DIR}/USER.md" | ||||||||||||||||||||||
| [ -f "${MEMSEARCH_DIR}/PROJECT.md" ] && printf 'Project review: %s\n' "${MEMSEARCH_DIR}/PROJECT.md" | ||||||||||||||||||||||
| printf 'Recent memory:\n%s\n' "${recent_memories}" | ||||||||||||||||||||||
| )" | ||||||||||||||||||||||
| if printf '%s' "${prompt}" | claude -p \ | ||||||||||||||||||||||
| --strict-mcp-config \ | ||||||||||||||||||||||
| --no-session-persistence \ | ||||||||||||||||||||||
| --model haiku \ | ||||||||||||||||||||||
| --effort low \ | ||||||||||||||||||||||
| --allowed-tools "Skill,Read,Write,Edit,Glob,Grep" \ | ||||||||||||||||||||||
| --allowed-tools "Read,Write,Edit,Glob,Grep" \ | ||||||||||||||||||||||
| --append-system-prompt-file "${PROMPT_FILE}" \ | ||||||||||||||||||||||
| --add-dir "${WIKI_DIR}" \ | ||||||||||||||||||||||
| --add-dir "${MEMSEARCH_DIR}" \ | ||||||||||||||||||||||
| "Wiki directory: ${WIKI_DIR} | ||||||||||||||||||||||
| Recently changed journal files: | ||||||||||||||||||||||
| ${recent_journals}${extra_context}" \ | ||||||||||||||||||||||
| >/dev/null 2>&1; then | ||||||||||||||||||||||
| date +%Y-%m-%d >"${STATE_FILE}" | ||||||||||||||||||||||
| fi | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 244
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 378
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 205
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 4416
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 5420
🏁 Script executed:
Repository: yxtay/dotfiles
Length of output: 6083
mkdir lock can leave the hook disabled forever. If the process is killed before the
EXITtrap runs,.okf-wiki-maintenance.lockremains and every later invocation immediately exits 0 with no logging. Add stale-lock recovery or another expiry path.🤖 Prompt for AI Agents