* feat: Add Claude Code integration plugin Complete port of hindsight-openclaw (v0.4.19) adapted to Claude Code's hook-based plugin architecture. Pure Python stdlib, no external dependencies. - Auto-recall via UserPromptSubmit hook (additionalContext injection) - Auto-retain via async Stop hook (chunked retention with sliding window) - Daemon management (auto-start/stop hindsight-embed via uvx) - Dynamic bank IDs with per-agent/project/channel/user granularity - All 34 configuration options with env var overrides - File-based state persistence with fcntl locking - Graceful degradation on all error paths Works with Claude Code Channels (Telegram, Discord, Slack) and interactive sessions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: Set correct chunked retention defaults (10/2, not 1/0) retainEveryNTurns=10 and retainOverlapTurns=2 are the production-tested values — every 10 turns, retain a 12-turn sliding window. The previous defaults (1/0) would retain every single turn with no overlap, defeating the chunked retention design that prevents API bombardment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: Align recallBudget and daemonIdleTimeout with Openclaw defaults recallBudget: "low" → "mid" (Openclaw default) daemonIdleTimeout: 300 → 0 (Openclaw default, never auto-stop) As an official Hindsight integration, defaults should match Openclaw. Users can optimize locally via settings.json or env vars. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
43 lines
986 B
Python
Executable file
43 lines
986 B
Python
Executable file
#!/usr/bin/env python3
|
|
"""SessionEnd hook: daemon cleanup.
|
|
|
|
Fires once when a Claude Code session terminates. If the plugin
|
|
auto-started a hindsight-embed daemon, this is where we stop it.
|
|
|
|
Port of: Openclaw's service.stop() in index.js
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from lib.config import debug_log, load_config
|
|
from lib.daemon import stop_daemon
|
|
|
|
|
|
def main():
|
|
config = load_config()
|
|
|
|
# Consume stdin
|
|
try:
|
|
hook_input = json.load(sys.stdin)
|
|
except (json.JSONDecodeError, EOFError):
|
|
hook_input = {}
|
|
|
|
debug_log(config, f"SessionEnd hook, reason: {hook_input.get('reason', 'unknown')}")
|
|
|
|
# Stop daemon if we started it
|
|
def _dbg(*a):
|
|
debug_log(config, *a)
|
|
|
|
stop_daemon(config, debug_fn=_dbg)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except Exception as e:
|
|
print(f"[Hindsight] SessionEnd error: {e}", file=sys.stderr)
|
|
sys.exit(0)
|