mirror of
https://github.com/alirezarezvani/claude-skills.git
synced 2026-08-28 04:24:58 +00:00
A ninth review pass found scheduler.py's schedule()/unschedule() both
located "this project's" managed cron line via marker not in ln, a
bare substring test, not an exact-match or delimiter-anchored check.
Failure scenario: two projects scheduled where one path is a literal
prefix of the other (e.g. /home/user/app and /home/user/app-v2) --
"# project=/home/user/app" is itself a substring of
"# project=/home/user/app-v2"'s line. Running schedule() or
unschedule() for /home/user/app would silently drop app-v2's cron
entry too, with no error or warning.
harvest.py's _project_matches() (added in this same PR) already gets
this right via delimiter-anchored comparison; scheduler.py's marker
matching didn't follow the same discipline.
Fixed: added _line_matches_project(), anchored on
ln.rstrip().endswith(marker) since the marker is always the last token
of a generated line -- used at both call sites.
Also fixed the related minor nit: install-cron.sh's printed --backend
value was unquoted next to otherwise-quoted ${RUNNER}/${PROJECT} in
its heredoc (low risk since that script only prints a line for the
user to copy, never executes anything itself, but inconsistent with
the quoting discipline everywhere else).
Verified two ways: a standalone reproduction confirmed the bug before
the fix and its absence after, and a full schedule()/unschedule()
round-trip through the actual public API (crontab -l/crontab - swapped
for an in-memory fake) confirmed scheduling both /home/user/app and
/home/user/app-v2, then unscheduling only app, correctly leaves
app-v2's line intact.
Added as README deviations #20-21 and reconciled the count across all
three documents to 21 (6 cosmetic, 15 safety/hardening) across nine
review rounds -- cross-checked with grep.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
29 lines
1.5 KiB
Bash
Executable file
29 lines
1.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Print (does NOT install) a crontab line that runs SkillOpt-Sleep nightly.
|
|
# The user copies the line into `crontab -e` if they want it.
|
|
set -euo pipefail
|
|
|
|
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
RUNNER="$PLUGIN_ROOT/scripts/sleep.sh"
|
|
PROJECT="${1:-$(pwd)}"
|
|
BACKEND="${2:-mock}"
|
|
|
|
# 3:17am local — deliberately off the :00 mark so many users don't all hit the
|
|
# API at once (and we leave room for jitter).
|
|
MIN=17
|
|
HOUR=3
|
|
|
|
cat <<EOF
|
|
# ── SkillOpt-Sleep nightly cycle ────────────────────────────────────────────
|
|
# Review past sessions, replay tasks, stage validated memory/skill updates.
|
|
# Runs at ${HOUR}:$(printf '%02d' $MIN) local every day. Output goes to the project's
|
|
# .skillopt-sleep/ dir; nothing live is changed until you run '/skillopt-sleep adopt'
|
|
# (unless you pass --auto-adopt below).
|
|
#
|
|
# Copy the next line into 'crontab -e':
|
|
${MIN} ${HOUR} * * * "${RUNNER}" run --project "${PROJECT}" --scope invoked --backend "${BACKEND}" >> "${PROJECT}/.skillopt-sleep/cron.log" 2>&1
|
|
#
|
|
# For fully-autonomous adoption (power users), append: --auto-adopt
|
|
# To spend real API budget for genuine lift, set BACKEND=anthropic above.
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
EOF
|