#!/bin/bash
# Pre-compact hook: Save critical state before context window compression.
#
# Writes a "## Checkpoints" entry to aiwiki/sessions/{date}-{session_id_short}.md
# which is the canonical per-session handoff file. The session file is created
# lazily on the first event (this hook, /wrap, /dream, or harden's session write).
#
# Reads session_id from Claude Code's PreCompact hook payload (stdin JSON).
# Falls back to "0000000" short id if stdin payload is missing or malformed —
# the file is still created, just without traceable session linkage.
#
# Recovery path: post-compact agent (and the next SessionStart) reads the
# latest aiwiki/sessions/*.md, looks at ## Checkpoints, and acts on any
# `Status: unconsumed` directive.
#
# Notepad (.forge/state/notepad.md) — REMOVED in v6.2. The single source of
# truth for session recovery state is now aiwiki/sessions/{date}-{id}.md.
# See templates/aiwiki/schemas/session.md (schema v2) for the file shape.
#
# Also logs the compaction event to .forge/state/telemetry.jsonl. The
# work_id field follows telemetry.sh's shape (emit only when an in-progress
# manifest resolves; omit otherwise) so gate-enforcer.sh and any future
# work-scoped consumer treat all telemetry records uniformly.

set -euo pipefail

# Read stdin JSON payload (Claude Code's hook contract). The payload includes
# session_id, transcript_path, cwd, hook_event_name, trigger. We need session_id.
PAYLOAD="$(cat 2>/dev/null || true)"

# Extract session_id via sed (no jq dependency). UUID format expected.
SESSION_ID=""
if [ -n "$PAYLOAD" ]; then
    SESSION_ID="$(echo "$PAYLOAD" | sed -n 's/.*"session_id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)"
fi
SESSION_ID_SHORT="${SESSION_ID:0:7}"
if [ -z "$SESSION_ID_SHORT" ]; then
    SESSION_ID_SHORT="0000000"
fi

# Find project root
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
STATE_DIR="$PROJECT_ROOT/.forge/state"
mkdir -p "$STATE_DIR"

# Find active work item (status: in-progress)
ACTIVE_WORK=""
MANIFEST_PATH=""

if [ -d "$PROJECT_ROOT/.forge/work" ]; then
    for manifest in "$PROJECT_ROOT/.forge/work"/*/*/manifest.yaml; do
        if [ -f "$manifest" ] && grep -q 'status: in-progress' "$manifest" 2>/dev/null; then
            WORK_NAME="$(basename "$(dirname "$manifest")")"
            WORK_TYPE="$(basename "$(dirname "$(dirname "$manifest")")")"
            ACTIVE_WORK="$WORK_TYPE/$WORK_NAME"
            MANIFEST_PATH="$manifest"
            break
        fi
    done
fi

# Detect recent aiwiki/ activity (24h window) for dream-directive decision
RECENT_AIWIKI_CHANGES=0
if [ -d "$PROJECT_ROOT/aiwiki" ]; then
    if [ -d "$PROJECT_ROOT/aiwiki/raw" ] && [ -n "$(find "$PROJECT_ROOT/aiwiki/raw" -type f -name '*.md' -mtime -1 2>/dev/null | head -1)" ]; then
        RECENT_AIWIKI_CHANGES=1
    fi
    if [ "$RECENT_AIWIKI_CHANGES" -eq 0 ]; then
        for typed in gotchas decisions conventions architecture oracles; do
            if [ -d "$PROJECT_ROOT/aiwiki/$typed" ] && [ -n "$(find "$PROJECT_ROOT/aiwiki/$typed" -type f -name '*.md' -mtime -1 2>/dev/null | head -1)" ]; then
                RECENT_AIWIKI_CHANGES=1
                break
            fi
        done
    fi
fi

# Session file path
TODAY="$(date -u '+%Y-%m-%d')"
TIMESTAMP="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
SESSIONS_DIR="$PROJECT_ROOT/aiwiki/sessions"
SESSION_FILE="$SESSIONS_DIR/${TODAY}-${SESSION_ID_SHORT}.md"

# If aiwiki/ doesn't exist (forge installed but never bootstrapped), skip
# session-file write entirely — there's nowhere to put it. Telemetry still logs.
if [ -d "$PROJECT_ROOT/aiwiki" ]; then
    mkdir -p "$SESSIONS_DIR"

    # Lazy-create session file with bare frontmatter if missing
    if [ ! -f "$SESSION_FILE" ]; then
        FOCUS_INIT="${ACTIVE_WORK:-unset}"
        {
            echo "---"
            echo "schema_id: session"
            echo "schema_version: 2"
            echo "status: active"
            echo "date_start: $TODAY"
            echo "session_id: ${SESSION_ID:-unknown}"
            echo "focus: $FOCUS_INIT"
            echo "last_commit: ~"
            echo "---"
            echo ""
            echo "## Checkpoints"
            echo ""
        } > "$SESSION_FILE"
    fi

    # Append PreCompact checkpoint entry
    {
        echo "### PreCompact at $TIMESTAMP"
        echo ""
        if [ -n "$ACTIVE_WORK" ]; then
            echo "Active work: $ACTIVE_WORK"
            echo "Manifest: $MANIFEST_PATH"
            echo ""
            if [ -f "$MANIFEST_PATH" ]; then
                echo "Phase status (from manifest):"
                echo '```yaml'
                grep -A 1 'status:\|gate-passed:\|locked_at:' "$MANIFEST_PATH" 2>/dev/null | head -30
                echo '```'
                echo ""
            fi
        else
            echo "Active work: none (no in-progress manifest found)"
            echo ""
        fi

        if [ "$RECENT_AIWIKI_CHANGES" -eq 1 ]; then
            echo "**Dream directive (unconsumed):**"
            echo ""
            echo "- Scope: \`aiwiki/raw/\` + typed pages touched in the last 24h (gotchas/, conventions/, etc.)"
            echo "- Trigger: \`pre-compact\`, context ~85%"
            echo "- Action: invoke \`support-dream\` skill before resuming other work"
            echo "- Session-file refinement: if this file's other sections (Files touched, Decisions, etc.) exist, dream may also refine them"
            echo ""
            echo "Mark consumed: after invoking dream, change this entry's header from \`**Dream directive (unconsumed):**\` to \`**Dream directive (consumed at {ISO-timestamp}):**\`. Header-flip is what session-start.sh counts; appending a 'Status: consumed' line leaves the original header in place and the next session-start still surfaces it as unconsumed."
            echo ""
        fi

        echo "---"
        echo ""
    } >> "$SESSION_FILE"

    echo "Pre-compact: appended checkpoint to $SESSION_FILE" >&2
else
    echo "Pre-compact: aiwiki/ not present — skipped session checkpoint. Telemetry logged." >&2
fi

# Log compaction event to telemetry. work_id field matches telemetry.sh's
# shape (P0-5): emitted only when an in-progress manifest resolves; omitted
# otherwise so the consuming side treats it as null uniformly.
TELEMETRY_FILE="$STATE_DIR/telemetry.jsonl"
WORK_FIELD=""
if [ -n "$ACTIVE_WORK" ]; then
    WORK_FIELD=",\"work_id\":\"$ACTIVE_WORK\""
fi
SESSION_JSON="${SESSION_ID:-null}"
if [ -n "$SESSION_ID" ]; then SESSION_JSON="\"$SESSION_ID\""; fi

echo "{\"event\":\"compact\",\"timestamp\":\"$TIMESTAMP\"$WORK_FIELD,\"session_id\":$SESSION_JSON,\"aiwiki_active\":$RECENT_AIWIKI_CHANGES}" >> "$TELEMETRY_FILE"

exit 0
