Files
bootstrap/tools/orchestrator/continue-prompt.sh
Jason Woltje abead17e0e feat: add multi-runtime support (coord run, prdy --codex) and next-task capsule
- coord/prdy subcommands now accept --claude/--codex runtime flags
- New `mosaic coord run` generates continuation context and launches
  selected runtime, replacing manual copy/paste workflow
- Next-task capsule (.mosaic/orchestrator/next-task.json) provides
  machine-readable execution context for deterministic session launches
- Codex strict orchestrator profile added to runtime/codex/RUNTIME.md
- Orchestrator protocol updated with between-session run flow
- New smoke-test.sh for orchestration behavior verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:27:09 -06:00

174 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
#
# continue-prompt.sh — Generate continuation prompt for next orchestrator session
#
# Usage:
# continue-prompt.sh [--project <path>] [--milestone <id>] [--copy]
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_lib.sh"
# ─── Parse arguments ─────────────────────────────────────────────────────────
PROJECT="."
MILESTONE=""
COPY=false
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT="$2"; shift 2 ;;
--milestone) MILESTONE="$2"; shift 2 ;;
--copy) COPY=true; shift ;;
-h|--help)
echo "Usage: continue-prompt.sh [--project <path>] [--milestone <id>] [--copy]"
exit 0
;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
done
_require_jq
require_mission "$PROJECT"
target_runtime="$(coord_runtime)"
launch_cmd="$(coord_launch_command)"
# ─── Load mission data ──────────────────────────────────────────────────────
mission="$(load_mission "$PROJECT")"
mission_name="$(echo "$mission" | jq -r '.name')"
mission_id="$(echo "$mission" | jq -r '.mission_id')"
quality_gates="$(echo "$mission" | jq -r '.quality_gates // "—"')"
project_path="$(echo "$mission" | jq -r '.project_path')"
# Determine current milestone
if [[ -n "$MILESTONE" ]]; then
current_ms_id="$MILESTONE"
else
current_ms_id="$(current_milestone_id "$PROJECT")"
fi
current_ms_name=""
if [[ -n "$current_ms_id" ]]; then
current_ms_name="$(milestone_name "$PROJECT" "$current_ms_id")"
fi
# Task counts
task_counts="$(count_tasks_md "$PROJECT")"
tasks_total="$(echo "$task_counts" | jq '.total')"
tasks_done="$(echo "$task_counts" | jq '.done')"
pct=0
(( tasks_total > 0 )) && pct=$(( (tasks_done * 100) / tasks_total ))
# Next task
next_task="$(find_next_task "$PROJECT")"
# Current branch
current_branch=""
if git -C "$PROJECT" rev-parse --is-inside-work-tree &>/dev/null; then
current_branch="$(git -C "$PROJECT" branch --show-current 2>/dev/null || echo "—")"
fi
# Previous session info
session_count="$(echo "$mission" | jq '.sessions | length')"
prev_session_id="—"
prev_runtime="—"
prev_duration="—"
prev_ended_reason="—"
prev_last_task="—"
if (( session_count > 0 )); then
last_idx=$(( session_count - 1 ))
prev_session_id="$(echo "$mission" | jq -r ".sessions[$last_idx].session_id // \"—\"")"
prev_runtime="$(echo "$mission" | jq -r ".sessions[$last_idx].runtime // \"—\"")"
prev_ended_reason="$(echo "$mission" | jq -r ".sessions[$last_idx].ended_reason // \"—\"")"
prev_last_task="$(echo "$mission" | jq -r ".sessions[$last_idx].last_task_id // \"—\"")"
s_start="$(echo "$mission" | jq -r ".sessions[$last_idx].started_at // \"\"")"
s_end="$(echo "$mission" | jq -r ".sessions[$last_idx].ended_at // \"\"")"
if [[ -n "$s_start" && -n "$s_end" && "$s_end" != "" ]]; then
s_epoch="$(iso_to_epoch "$s_start")"
e_epoch="$(iso_to_epoch "$s_end")"
if (( e_epoch > 0 && s_epoch > 0 )); then
prev_duration="$(format_duration $(( e_epoch - s_epoch )))"
fi
fi
fi
# Write machine-readable next-task capsule for deterministic runtime launches.
write_next_task_capsule \
"$PROJECT" \
"$target_runtime" \
"$mission_id" \
"$mission_name" \
"$project_path" \
"$quality_gates" \
"$current_ms_id" \
"$current_ms_name" \
"$next_task" \
"$tasks_done" \
"$tasks_total" \
"$pct" \
"$current_branch"
# ─── Generate prompt ────────────────────────────────────────────────────────
prompt="$(cat <<EOF
## Continuation Mission
Continue **$mission_name** from existing state.
## Setup
- **Project:** $project_path
- **State:** docs/TASKS.md (already populated — ${tasks_done}/${tasks_total} tasks complete)
- **Manifest:** docs/MISSION-MANIFEST.md
- **Scratchpad:** docs/scratchpads/${mission_id}.md
- **Protocol:** ~/.config/mosaic/guides/ORCHESTRATOR.md
- **Quality gates:** $quality_gates
- **Target runtime:** $target_runtime
## Resume Point
- **Current milestone:** ${current_ms_name:-—} (${current_ms_id:-—})
- **Next task:** ${next_task:-—}
- **Progress:** ${tasks_done}/${tasks_total} tasks (${pct}%)
- **Branch:** ${current_branch:-—}
## Previous Session Context
- **Session:** $prev_session_id ($prev_runtime, $prev_duration)
- **Ended:** $prev_ended_reason
- **Last completed task:** $prev_last_task
## Instructions
1. Read \`~/.config/mosaic/guides/ORCHESTRATOR.md\` for full protocol
2. Read \`docs/MISSION-MANIFEST.md\` for mission scope and status
3. Read \`docs/scratchpads/${mission_id}.md\` for session history and decisions
4. Read \`docs/TASKS.md\` for current task state
5. \`git pull --rebase\` to sync latest changes
6. Launch runtime with \`$launch_cmd\`
7. Continue execution from task **${next_task:-next-pending}**
8. Follow Two-Phase Completion Protocol
9. You are the SOLE writer of \`docs/TASKS.md\`
EOF
)"
# ─── Output ──────────────────────────────────────────────────────────────────
if [[ "$COPY" == true ]]; then
if command -v wl-copy &>/dev/null; then
echo "$prompt" | wl-copy
echo -e "${C_GREEN}Continuation prompt copied to clipboard (wl-copy)${C_RESET}" >&2
elif command -v xclip &>/dev/null; then
echo "$prompt" | xclip -selection clipboard
echo -e "${C_GREEN}Continuation prompt copied to clipboard (xclip)${C_RESET}" >&2
else
echo -e "${C_YELLOW}No clipboard tool found (wl-copy or xclip). Printing to stdout.${C_RESET}" >&2
echo "$prompt"
fi
else
echo "$prompt"
fi