diff --git a/plugins/claude-code/commands/oac-setup.md b/plugins/claude-code/commands/oac-setup.md index 01d0a1d..3b20752 100644 --- a/plugins/claude-code/commands/oac-setup.md +++ b/plugins/claude-code/commands/oac-setup.md @@ -11,7 +11,7 @@ Download context files from the OpenAgents Control repository to enable context- ## Download Progress -!`bash ${CLAUDE_PLUGIN_ROOT}/scripts/download-context.sh $ARGUMENTS` +!`${CLAUDE_PLUGIN_ROOT}/scripts/download-context.sh $ARGUMENTS` ## What Was Downloaded diff --git a/plugins/claude-code/hooks/session-start.sh b/plugins/claude-code/hooks/session-start.sh index 09d397d..521523d 100644 --- a/plugins/claude-code/hooks/session-start.sh +++ b/plugins/claude-code/hooks/session-start.sh @@ -1,226 +1,47 @@ -#!/bin/bash +#!/usr/bin/env bash # SessionStart hook for OAC plugin -# Injects using-oac skill and checks .tmp cleanup, .oac config, and context installation set -euo pipefail -# Resolve plugin root directory -PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +# Determine plugin root directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" +PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" SKILL_FILE="${PLUGIN_ROOT}/skills/using-oac/SKILL.md" -TMP_SESSIONS_DIR=".tmp/sessions" -CONTEXT_MANIFEST=".context-manifest.json" -OAC_EXAMPLE="${PLUGIN_ROOT}/.oac.example" -# Load using-oac skill content -if [[ ! -f "${SKILL_FILE}" ]]; then - echo '{"error": "using-oac skill not found at '"${SKILL_FILE}"'"}' >&2 - exit 1 +# Read using-oac content +using_oac_content=$(cat "${SKILL_FILE}" 2>&1 || echo "Error reading using-oac skill") + +# Escape string for JSON embedding using bash parameter substitution +# Each ${s//old/new} is a single C-level pass - orders of magnitude +# faster than character-by-character loop +escape_for_json() { + local s="$1" + s="${s//\\/\\\\}" + s="${s//\"/\\\"}" + s="${s//$'\n'/\\n}" + s="${s//$'\r'/\\r}" + s="${s//$'\t'/\\t}" + printf '%s' "$s" +} + +using_oac_escaped=$(escape_for_json "$using_oac_content") + +# Build warning message for first-time users +warning_message="" +if [[ ! -f ".context-manifest.json" ]]; then + warning_message="\n\nIN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:👋 **Welcome to OpenAgents Control!** To get started, run /oac:setup to download context files. Then use /oac:help to learn the 6-stage workflow." fi -SKILL_CONTENT=$(cat "${SKILL_FILE}") +warning_escaped=$(escape_for_json "$warning_message") -# Escape for JSON using parameter substitution (fast method) -# Replace backslash, double-quote, newline, tab, carriage return -SKILL_CONTENT="${SKILL_CONTENT//\\/\\\\}" # Backslash -SKILL_CONTENT="${SKILL_CONTENT//\"/\\\"}" # Double-quote -SKILL_CONTENT="${SKILL_CONTENT//$'\n'/\\n}" # Newline -SKILL_CONTENT="${SKILL_CONTENT//$'\t'/\\t}" # Tab -SKILL_CONTENT="${SKILL_CONTENT//$'\r'/\\r}" # Carriage return - -# Check for .oac configuration -CONFIG_EXISTS=false -CONFIG_LOCATION="" -RECOMMENDATIONS=() - -if [[ -f ".oac" ]]; then - CONFIG_EXISTS=true - CONFIG_LOCATION="project (.oac)" -elif [[ -f "$HOME/.oac" ]]; then - CONFIG_EXISTS=true - CONFIG_LOCATION="global (~/.oac)" -else - RECOMMENDATIONS+=("Copy .oac.example to .oac to customize settings") -fi - -# Check for context installation -CONTEXT_INSTALLED=false -CONTEXT_AGE_DAYS=0 -CONTEXT_WARNING="" - -if [[ -f "${CONTEXT_MANIFEST}" ]]; then - CONTEXT_INSTALLED=true - - # Check age of context manifest (>30 days = suggest update) - if [[ "$(uname)" == "Darwin" ]]; then - # macOS - MANIFEST_MTIME=$(stat -f %m "${CONTEXT_MANIFEST}" 2>/dev/null || echo 0) - else - # Linux - MANIFEST_MTIME=$(stat -c %Y "${CONTEXT_MANIFEST}" 2>/dev/null || echo 0) - fi - - CURRENT_TIME=$(date +%s) - CONTEXT_AGE_DAYS=$(( (CURRENT_TIME - MANIFEST_MTIME) / 86400 )) - - if [[ ${CONTEXT_AGE_DAYS} -gt 30 ]]; then - CONTEXT_WARNING="⚠️ Context is ${CONTEXT_AGE_DAYS} days old. Consider running /oac:setup --core to update." - RECOMMENDATIONS+=("Run /oac:setup --core to update context (${CONTEXT_AGE_DAYS} days old)") - fi -else - RECOMMENDATIONS+=("Run /oac:setup --core to download context files") -fi - -# Detect first-time user -FIRST_TIME_USER=false -if [[ "${CONFIG_EXISTS}" == "false" ]] && [[ "${CONTEXT_INSTALLED}" == "false" ]]; then - FIRST_TIME_USER=true -fi - -# Check .tmp/ cleanup needs -CLEANUP_SCRIPT="${PLUGIN_ROOT}/scripts/cleanup-tmp.sh" -CLEANUP_WARNING="" - -if [[ -x "${CLEANUP_SCRIPT}" ]]; then - # Check for old .tmp files - OLD_SESSIONS=0 - OLD_TASKS=0 - OLD_EXTERNAL=0 - - # Count old sessions (>7 days) - if [[ -d ".tmp/sessions" ]]; then - OLD_SESSIONS=$(find ".tmp/sessions" -mindepth 1 -maxdepth 1 -type d -mtime +7 2>/dev/null | wc -l | tr -d ' ') - fi - - # Count old completed tasks (>30 days) - if [[ -d ".tmp/tasks" ]]; then - for task_dir in .tmp/tasks/*; do - if [[ ! -d "$task_dir" ]]; then continue; fi - - all_completed=true - has_subtasks=false - - for subtask_file in "$task_dir"/subtask_*.json; do - if [[ ! -f "$subtask_file" ]]; then continue; fi - has_subtasks=true - - if ! grep -q '"status": "completed"' "$subtask_file" 2>/dev/null; then - all_completed=false - break - fi - - if [[ $(find "$subtask_file" -mtime +30 2>/dev/null | wc -l) -eq 0 ]]; then - all_completed=false - break - fi - done - - if [[ "$has_subtasks" == "true" ]] && [[ "$all_completed" == "true" ]]; then - ((OLD_TASKS++)) - fi - done - fi - - # Count old external context (>7 days) - if [[ -d ".tmp/external-context" ]]; then - OLD_EXTERNAL=$(find ".tmp/external-context" -mindepth 1 -maxdepth 1 -type d -mtime +7 2>/dev/null | wc -l | tr -d ' ') - fi - - TOTAL_OLD=$((OLD_SESSIONS + OLD_TASKS + OLD_EXTERNAL)) - - if [[ ${TOTAL_OLD} -gt 0 ]]; then - CLEANUP_WARNING="⚠️ Found ${TOTAL_OLD} old temporary items (${OLD_SESSIONS} sessions, ${OLD_TASKS} tasks, ${OLD_EXTERNAL} external cache). Run cleanup script to review: bash ${CLEANUP_SCRIPT}" - RECOMMENDATIONS+=("Run cleanup script to remove old temporary files") - fi -fi - -# Build context injection message -CONTEXT_MESSAGE="# OpenAgents Control (OAC) Workflow - -**EXTREMELY_IMPORTANT**: This skill is automatically loaded for every development task. - -${SKILL_CONTENT}" - -# Add first-time user welcome -if [[ "${FIRST_TIME_USER}" == "true" ]]; then - CONTEXT_MESSAGE="${CONTEXT_MESSAGE} - ---- - -## 👋 Welcome to OpenAgents Control! - -This appears to be your first time using OAC. Here's how to get started: - -1. **Download context files**: Run \`/oac:setup --core\` to get coding standards and patterns -2. **Customize settings**: Copy \`.oac.example\` to \`.oac\` to configure your preferences -3. **Learn the workflow**: Run \`/oac:help\` to see the 6-stage development workflow - -Once context is installed, OAC will automatically discover relevant standards and patterns for every task." -fi - -# Add context warning if needed -if [[ -n "${CONTEXT_WARNING}" ]]; then - CONTEXT_MESSAGE="${CONTEXT_MESSAGE} - ---- - -${CONTEXT_WARNING}" -fi - -# Add cleanup warning if needed -if [[ -n "${CLEANUP_WARNING}" ]]; then - CONTEXT_MESSAGE="${CONTEXT_MESSAGE} - ---- - -${CLEANUP_WARNING}" -fi - -# Escape context message for JSON -CONTEXT_MESSAGE="${CONTEXT_MESSAGE//\\/\\\\}" -CONTEXT_MESSAGE="${CONTEXT_MESSAGE//\"/\\\"}" -CONTEXT_MESSAGE="${CONTEXT_MESSAGE//$'\n'/\\n}" -CONTEXT_MESSAGE="${CONTEXT_MESSAGE//$'\t'/\\t}" -CONTEXT_MESSAGE="${CONTEXT_MESSAGE//$'\r'/\\r}" - -# Build recommendations JSON array -RECOMMENDATIONS_JSON="[" -FIRST_REC=true -for rec in "${RECOMMENDATIONS[@]}"; do - if [[ "${FIRST_REC}" == "true" ]]; then - FIRST_REC=false - else - RECOMMENDATIONS_JSON="${RECOMMENDATIONS_JSON}," - fi - # Escape recommendation for JSON - REC_ESCAPED="${rec//\\/\\\\}" - REC_ESCAPED="${REC_ESCAPED//\"/\\\"}" - RECOMMENDATIONS_JSON="${RECOMMENDATIONS_JSON}\"${REC_ESCAPED}\"" -done -RECOMMENDATIONS_JSON="${RECOMMENDATIONS_JSON}]" - -# Output JSON with hookSpecificOutput format +# Output context injection as JSON cat <OAC workflow is active. Follow 6-stage process: Analyze, Plan & Approve, LoadContext, Execute, Validate, Complete.", - "firstTimeUser": ${FIRST_TIME_USER}, - "contextInstalled": ${CONTEXT_INSTALLED}, - "contextAgeDays": ${CONTEXT_AGE_DAYS}, - "configExists": ${CONFIG_EXISTS}, - "configLocation": "${CONFIG_LOCATION}", - "recommendations": ${RECOMMENDATIONS_JSON}, - "contextInjection": { - "priority": "EXTREMELY_IMPORTANT", - "content": "${CONTEXT_MESSAGE}" - }, - "tmpCleanup": { - "oldSessions": ${OLD_SESSIONS:-0}, - "oldTasks": ${OLD_TASKS:-0}, - "oldExternal": ${OLD_EXTERNAL:-0}, - "total": ${TOTAL_OLD:-0}, - "warning": "${CLEANUP_WARNING}" - } + "additionalContext": "\nYou are using OpenAgents Control (OAC).\n\n**Below is the full content of your 'using-oac' skill - your guide to the 6-stage workflow. For all other skills, use the 'Skill' tool:**\n\n${using_oac_escaped}\n\n${warning_escaped}\n" } } EOF + +exit 0