Bug fixes: - #52: bundle run-sleep.sh in Claude Code plugin + 4-level fallback - #58: add skillopt-sleep console script entry point in pyproject.toml - #62: filter headless claude -p replay sessions from harvest Plugin sync (Claude Code / Codex / Copilot / OpenClaw): - Document all 22 CLI flags, 7 actions, 4 backends across all SKILL.md files - Document config keys (preferences, gate_mode, dream_rollouts, etc.) - Document memory consolidation (evolve_memory / evolve_skill) - Add schedule/unschedule to all plugins - Copilot MCP: expand schema from 3 → 16 params + schedule tools - OpenClaw: add schedule/unschedule subcommands via shared scheduler Tests: - Cross-plugin parity test (prevents future feature drift) - MCP schema completeness test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,39 @@ python3 run_sleep.py --dry-run
|
||||
python3 run_sleep.py --tasks tests/research-cron-tasks.json
|
||||
```
|
||||
|
||||
## Scheduling
|
||||
|
||||
```bash
|
||||
python3 slash_sleep.py schedule --hour 3 --minute 17
|
||||
python3 slash_sleep.py unschedule
|
||||
python3 slash_sleep.py unschedule --all
|
||||
```
|
||||
|
||||
Installs a nightly cron entry using the shared SkillOpt-Sleep scheduler. This is an alternative to the external `run_sleep_cron.sh` script.
|
||||
|
||||
## Alternative backends
|
||||
|
||||
While OpenClaw defaults to `openclaw-deepseek` (DeepSeek V4 Pro + Ollama), the shared engine also supports:
|
||||
- `--backend mock` — deterministic, no API spend (for testing)
|
||||
- `--backend claude` — uses the Claude CLI
|
||||
- `--backend codex` — uses the Codex CLI
|
||||
- `--backend copilot` — uses the GitHub Copilot CLI
|
||||
|
||||
These can be used via the engine directly (`python -m skillopt_sleep`).
|
||||
|
||||
## Shared-engine flags
|
||||
|
||||
When invoking the engine directly, all standard flags are available:
|
||||
- `--source codex` / `--source auto` — harvest from Codex Desktop sessions
|
||||
- `--tasks-file PATH` — use a pre-built task set
|
||||
- `--target-skill-path PATH` — explicit SKILL.md target
|
||||
- `--max-tasks N` / `--max-sessions N` — cap workload
|
||||
- `--progress` — print phase progress
|
||||
- `--json` — machine-readable output
|
||||
- `--auto-adopt` — auto-adopt if gate passes
|
||||
|
||||
Config keys: `preferences`, `gate_mode`, `gate_metric`, `dream_rollouts`, `recall_k`, `evolve_memory`, `evolve_skill`.
|
||||
|
||||
## Config (config.json)
|
||||
|
||||
Key knobs:
|
||||
|
||||
@@ -207,6 +207,30 @@ def reject(night: str = None) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def schedule_cmd(hour: int, minute: int) -> int:
|
||||
"""Install a nightly cron entry via the shared SkillOpt-Sleep scheduler."""
|
||||
try:
|
||||
from skillopt_sleep.scheduler import schedule
|
||||
except ImportError:
|
||||
print("ERROR: skillopt_sleep.scheduler not available — is SkillOpt-Sleep installed?")
|
||||
return 1
|
||||
result = schedule(hour=hour, minute=minute)
|
||||
print(result)
|
||||
return 0
|
||||
|
||||
|
||||
def unschedule_cmd(all_projects: bool) -> int:
|
||||
"""Remove cron entry via the shared SkillOpt-Sleep scheduler."""
|
||||
try:
|
||||
from skillopt_sleep.scheduler import unschedule
|
||||
except ImportError:
|
||||
print("ERROR: skillopt_sleep.scheduler not available — is SkillOpt-Sleep installed?")
|
||||
return 1
|
||||
result = unschedule(all_projects=all_projects)
|
||||
print(result)
|
||||
return 0
|
||||
|
||||
|
||||
def cost() -> int:
|
||||
"""Estimate per-night cost based on the actual measurement from Phase 2.
|
||||
|
||||
@@ -265,6 +289,12 @@ def main():
|
||||
p_reject = sub.add_parser("reject", help="discard most recent staging")
|
||||
p_reject.add_argument("night", nargs="?", default=None)
|
||||
sub.add_parser("cost", help="estimate cost")
|
||||
p_schedule = sub.add_parser("schedule", help="install nightly cron entry")
|
||||
p_schedule.add_argument("--hour", type=int, default=3, help="hour (0-23)")
|
||||
p_schedule.add_argument("--minute", type=int, default=0, help="minute (0-59)")
|
||||
p_unschedule = sub.add_parser("unschedule", help="remove cron entry")
|
||||
p_unschedule.add_argument("--all", dest="all_projects", action="store_true",
|
||||
help="remove entries for all projects")
|
||||
|
||||
args = ap.parse_args()
|
||||
|
||||
@@ -282,6 +312,10 @@ def main():
|
||||
return reject(args.night)
|
||||
if args.cmd == "cost":
|
||||
return cost()
|
||||
if args.cmd == "schedule":
|
||||
return schedule_cmd(args.hour, args.minute)
|
||||
if args.cmd == "unschedule":
|
||||
return unschedule_cmd(args.all_projects)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user