#!/usr/bin/env bash
# Purpose: State machine for /prompt command orchestration
# Inputs: Structured XML via stdin OR command-line args for initial state
# Outputs: Next instruction for /prompt command
# Architecture: State machine that guides /prompt through:
# - Without --plan: optimizer → executor → done
# - With --plan: optimizer → Plan agent → executor → done
set -euo pipefail
# Source common functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$SCRIPT_DIR/../../scripts/common.sh"
# Detect current state from input
detect_state() {
local input="$1"
if echo "$input" | grep -q ""; then
echo "post_template_selector"
elif echo "$input" | grep -q ""; then
echo "post_optimizer"
elif echo "$input" | grep -q ""; then
echo "post_plan"
elif echo "$input" | grep -q ""; then
echo "final"
else
# Initial state (command-line args or initial XML)
echo "initial"
fi
}
# Parse flags from initial task description
# Sets global variables: RETURN_ONLY, PLAN, TEMPLATE, TEMPLATE_FLAG_SEEN, TASK_DESCRIPTION
parse_initial_flags() {
local raw_input="$1"
# Set global variables for use by handler functions
RETURN_ONLY=false
PLAN=false
TEMPLATE=""
TEMPLATE_FLAG_SEEN=false
# Parse all flags from the beginning of the input
while true; do
case "$raw_input" in
--template=*)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="${raw_input#--template=}"
TEMPLATE="${TEMPLATE%% *}"
raw_input="${raw_input#--template=$TEMPLATE}"
raw_input="${raw_input# }"
TEMPLATE_FLAG_SEEN=true
;;
--code\ *|--code)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
echo "Already set: $TEMPLATE" >&2
echo "Cannot use multiple template flags in one command." >&2
exit 1
fi
TEMPLATE="code-refactoring"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--code}"
raw_input="${raw_input# }"
;;
--refactor\ *|--refactor)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="code-refactoring"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--refactor}"
raw_input="${raw_input# }"
;;
--review\ *|--review)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="code-review"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--review}"
raw_input="${raw_input# }"
;;
--test\ *|--test)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="test-generation"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--test}"
raw_input="${raw_input# }"
;;
--docs\ *|--docs)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="documentation-generator"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--docs}"
raw_input="${raw_input# }"
;;
--documentation\ *|--documentation)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="documentation-generator"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--documentation}"
raw_input="${raw_input# }"
;;
--extract\ *|--extract)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="data-extraction"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--extract}"
raw_input="${raw_input# }"
;;
--compare\ *|--compare)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="code-comparison"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--compare}"
raw_input="${raw_input# }"
;;
--comparison\ *|--comparison)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="code-comparison"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--comparison}"
raw_input="${raw_input# }"
;;
--custom\ *|--custom)
if [ "$TEMPLATE_FLAG_SEEN" = true ]; then
echo "Error: Multiple template flags specified." >&2
exit 1
fi
TEMPLATE="custom"
TEMPLATE_FLAG_SEEN=true
raw_input="${raw_input#--custom}"
raw_input="${raw_input# }"
;;
--return-only\ *|--return-only)
RETURN_ONLY=true
raw_input="${raw_input#--return-only}"
raw_input="${raw_input# }"
;;
--plan\ *|--plan)
PLAN=true
raw_input="${raw_input#--plan}"
raw_input="${raw_input# }"
;;
*)
# No more flags, break out of loop
break
;;
esac
done
# Validate template name if provided
if [ -n "$TEMPLATE" ]; then
case "$TEMPLATE" in
code-refactoring|code-review|test-generation|documentation-generator|data-extraction|code-comparison|custom)
# Valid template
;;
*)
echo "Error: Invalid template name: $TEMPLATE" >&2
exit 1
;;
esac
fi
# Normalize whitespace and set global TASK_DESCRIPTION
raw_input=$(echo "$raw_input" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/[[:space:]][[:space:]]*/ /g')
TASK_DESCRIPTION="$raw_input"
}
# Handle initial state - spawn template-selector or prompt-optimizer
handle_initial_state() {
parse_initial_flags "$1"
# Sanitize for shell safety, then escape for CDATA safety
local sanitized_task=$(escape_cdata "$(sanitize_input "$TASK_DESCRIPTION")")
# If no template specified, spawn template-selector first
if [ -z "$TEMPLATE" ]; then
cat <
initial
spawn_template_selector
meta-prompt:template-selector
Select template for task
$sanitized_task
Follow your instructions to classify the task and return the result in XML format.]]>
...(full XML output)...
$sanitized_task
$PLAN
$RETURN_ONLY']]>
EOF
return
fi
# Template already specified, proceed to optimizer
# Determine execution mode
local execution_mode="direct"
if [ "$PLAN" = true ]; then
execution_mode="plan"
fi
# Build template XML
local template_xml="$TEMPLATE"
# Check if return-only mode
if [ "$RETURN_ONLY" = true ]; then
cat <
initial
spawn_optimizer_return_only
meta-prompt:prompt-optimizer
Create optimized prompt
$sanitized_task$template_xml
$execution_mode
Follow your instructions to process the template and return the result in XML format.]]>
present_optimized_prompt
EOF
else
cat <
initial
spawn_optimizer
meta-prompt:prompt-optimizer
Create optimized prompt
$sanitized_task$template_xml
$execution_mode
Follow your instructions to process the template and return the result in XML format.]]>
...(full XML output)...']]>
EOF
fi
}
# Handle post-template-selector state - spawn prompt-optimizer with selected template
handle_post_template_selector_state() {
local selector_output="$1"
# Extract values from XML using sed (BSD-compatible)
local selected_template=$(echo "$selector_output" | sed -n 's/.*\(.*\)<\/selected_template>.*/\1/p')
local original_task=$(echo "$selector_output" | sed -n 's/.*\(.*\)<\/original_task>.*/\1/p')
local plan_flag=$(echo "$selector_output" | sed -n 's/.*\(.*\)<\/plan_flag>.*/\1/p')
local return_only_flag=$(echo "$selector_output" | sed -n 's/.*\(.*\)<\/return_only_flag>.*/\1/p')
# Sanitize for shell safety, then escape for CDATA safety
local sanitized_task=$(escape_cdata "$(sanitize_input "$original_task")")
# Determine execution mode
local execution_mode="direct"
if [ "$plan_flag" = "true" ]; then
execution_mode="plan"
fi
# Build template XML
local template_xml="$selected_template"
# Check if return-only mode
if [ "$return_only_flag" = "true" ]; then
cat <
post_template_selector
spawn_optimizer_return_only
meta-prompt:prompt-optimizer
Create optimized prompt
$sanitized_task$template_xml
$execution_mode
Follow your instructions to process the template and return the result in XML format.]]>
present_optimized_prompt
EOF
else
cat <
post_template_selector
spawn_optimizer
meta-prompt:prompt-optimizer
Create optimized prompt
$sanitized_task$template_xml
$execution_mode
Follow your instructions to process the template and return the result in XML format.]]>
...(full XML output)...']]>
EOF
fi
}
# Handle post-optimizer state - spawn Plan or template-executor
handle_post_optimizer_state() {
local optimizer_output="$1"
# Extract values from XML using sed (BSD-compatible)
local skill=$(echo "$optimizer_output" | sed -n 's/.*\(.*\)<\/skill>.*/\1/p')
local execution_mode=$(echo "$optimizer_output" | sed -n 's/.*\(.*\)<\/execution_mode>.*/\1/p')
local optimized_prompt=$(echo "$optimizer_output" | sed -n 's/.*\(.*\)<\/optimized_prompt>.*/\1/p')
# Sanitize for shell safety, then escape for CDATA safety
local sanitized_skill=$(escape_cdata "$(sanitize_input "$skill")")
local sanitized_prompt=$(escape_cdata "$optimized_prompt")
if [ "$execution_mode" = "plan" ]; then
cat <
post_optimizer
spawn_plan_agent
Plan
Create execution plan
$sanitized_skill
$sanitized_prompt
']]>
EOF
else
cat <
post_optimizer
spawn_template_executor
meta-prompt:template-executor
Execute task
$sanitized_skill
$sanitized_prompt
Follow your instructions to load the skill (if not 'none') and execute the task.]]>
present_results
EOF
fi
}
# Handle post-plan state - spawn template-executor with the plan
handle_post_plan_state() {
local plan_output="$1"
# Extract values from XML using sed (BSD-compatible)
local skill=$(echo "$plan_output" | sed -n 's/.*\(.*\)<\/skill>.*/\1/p')
# Extract optimized_prompt (multiline content)
local optimized_prompt=$(echo "$plan_output" | sed -n '//,/<\/optimized_prompt>/p' | sed '1d;$d')
# Sanitize for shell safety, then escape for CDATA safety
local sanitized_skill=$(escape_cdata "$(sanitize_input "$skill")")
local sanitized_prompt=$(escape_cdata "$optimized_prompt")
cat <
post_plan
spawn_template_executor
meta-prompt:template-executor
Execute task
$sanitized_skill
$sanitized_prompt
Follow your instructions to load the skill (if not 'none') and execute the task.]]>
present_results
EOF
}
# Handle final state - just present results
handle_final_state() {
cat <
final
done
present_results
EOF
}
# Main state machine logic
main() {
# Check if input is provided as command-line arg
if [ $# -gt 0 ]; then
# Use command-line args
INPUT="$1"
# Detect state from input
STATE=$(detect_state "$INPUT")
else
# No input provided
echo "Error: No input provided. Usage: $0 ''" >&2
echo " Or: $0 ''" >&2
exit 1
fi
# Execute state handler
case "$STATE" in
initial)
handle_initial_state "$INPUT"
;;
post_template_selector)
handle_post_template_selector_state "$INPUT"
;;
post_optimizer)
handle_post_optimizer_state "$INPUT"
;;
post_plan)
handle_post_plan_state "$INPUT"
;;
final)
handle_final_state
;;
*)
echo "Error: Unknown state: $STATE" >&2
exit 1
;;
esac
}
# Run main function
main "$@"