184 lines
6.4 KiB
Bash
Executable File
184 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
BIN="${WSTONE_MCP_BIN:-$ROOT_DIR/editor/build-native/whetstone_mcp_stable}"
|
|
WORKSPACE="${WSTONE_WORKSPACE:-$ROOT_DIR}"
|
|
LANGUAGE="${WSTONE_LANGUAGE:-cpp}"
|
|
MAX_ITERS="${MAX_ITERS:-3}"
|
|
STRICT_MODE="${STRICT_MODE:-1}"
|
|
SPEC="${1:-}"
|
|
|
|
if [[ -z "$SPEC" ]]; then
|
|
echo "usage: $0 \"<generation spec>\""
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq >/dev/null 2>&1; then
|
|
echo "error: jq required"
|
|
exit 1
|
|
fi
|
|
|
|
OUT_DIR="${OUT_DIR:-$ROOT_DIR/logs/taskitem_runs/production_loop_$(date +%Y%m%d_%H%M%S)}"
|
|
mkdir -p "$OUT_DIR"
|
|
TRACE_FILE="$OUT_DIR/trace.jsonl"
|
|
|
|
call_tool() {
|
|
local tool_name="$1"
|
|
local args_json="$2"
|
|
local init_req tool_req responses tool_resp
|
|
init_req='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"production-loop","version":"1.0"}}}'
|
|
tool_req="$(jq -nc --arg t "$tool_name" --argjson a "$args_json" '{jsonrpc:"2.0",id:2,method:"tools/call",params:{name:$t,arguments:$a}}')"
|
|
responses="$(printf '%s\n%s\n' "$init_req" "$tool_req" | "$BIN" --workspace "$WORKSPACE" --language "$LANGUAGE" 2>/dev/null || true)"
|
|
tool_resp="$(printf '%s\n' "$responses" | tail -n1)"
|
|
printf '%s' "$tool_resp"
|
|
}
|
|
|
|
extract_json() {
|
|
local raw="$1"
|
|
printf '%s' "$raw" | jq -r '.result.content[0].text // "{}"' | jq '.'
|
|
}
|
|
|
|
log_trace() {
|
|
local phase="$1"
|
|
local iter="$2"
|
|
local payload="$3"
|
|
jq -nc --arg phase "$phase" --arg iter "$iter" --argjson payload "$payload" \
|
|
'{phase:$phase, iteration:$iter, payload:$payload}' >> "$TRACE_FILE"
|
|
}
|
|
|
|
loop_spec="$SPEC"
|
|
status="blocked"
|
|
blocked_reason="max_iterations_exhausted"
|
|
final_ready=0
|
|
|
|
for i in $(seq 1 "$MAX_ITERS"); do
|
|
iter_id="iter_$(printf '%02d' "$i")"
|
|
|
|
args="$(jq -nc --arg s "$loop_spec" '{spec:$s,preferImports:true}')"
|
|
raw="$(call_tool whetstone_generate_code "$args")"
|
|
printf '%s\n' "$raw" > "$OUT_DIR/${iter_id}_generate_raw.json"
|
|
parsed="$(extract_json "$raw")"
|
|
printf '%s\n' "$parsed" > "$OUT_DIR/${iter_id}_generate.json"
|
|
log_trace "generate" "$iter_id" "$parsed"
|
|
|
|
code="$(printf '%s' "$parsed" | jq -r '.generatedCode // ""')"
|
|
if [[ -z "$code" ]]; then
|
|
code="$(printf '%s' "$parsed" | jq -r '.note // ""')"
|
|
fi
|
|
printf '%s\n' "$code" > "$OUT_DIR/${iter_id}_generated_code.txt"
|
|
|
|
strict_arg=()
|
|
if [[ "$STRICT_MODE" == "1" ]]; then
|
|
strict_arg+=(--strict)
|
|
fi
|
|
|
|
python3 "$ROOT_DIR/tools/mcp/evaluate_generated_code_gates.py" \
|
|
--code-file "$OUT_DIR/${iter_id}_generated_code.txt" \
|
|
--language "$LANGUAGE" \
|
|
"${strict_arg[@]}" \
|
|
--out "$OUT_DIR/${iter_id}_gates.json" >/tmp/production_loop_gate_${i}.json
|
|
|
|
gates_payload="$(cat "$OUT_DIR/${iter_id}_gates.json")"
|
|
log_trace "gates" "$iter_id" "$gates_payload"
|
|
|
|
ready="$(jq -r '.gates.overall_ready' "$OUT_DIR/${iter_id}_gates.json")"
|
|
if [[ "$ready" == "true" ]]; then
|
|
status="green"
|
|
blocked_reason=""
|
|
final_ready=1
|
|
break
|
|
fi
|
|
|
|
# Deterministic C++ include repair attempt from diagnostics.
|
|
if [[ "$LANGUAGE" == "cpp" ]]; then
|
|
python3 "$ROOT_DIR/tools/mcp/apply_cpp_diagnostic_fixes.py" \
|
|
--code-file "$OUT_DIR/${iter_id}_generated_code.txt" \
|
|
--gates-json "$OUT_DIR/${iter_id}_gates.json" \
|
|
--out-code-file "$OUT_DIR/${iter_id}_generated_code_fixed.cpp" \
|
|
--out-report "$OUT_DIR/${iter_id}_fix_report.json" >/tmp/production_loop_fix_${i}.json
|
|
|
|
if [[ "$(jq -r '.changed' "$OUT_DIR/${iter_id}_fix_report.json")" == "true" ]]; then
|
|
mv "$OUT_DIR/${iter_id}_generated_code_fixed.cpp" "$OUT_DIR/${iter_id}_generated_code.txt"
|
|
fixed_gate="$OUT_DIR/${iter_id}_gates_after_fix.json"
|
|
python3 "$ROOT_DIR/tools/mcp/evaluate_generated_code_gates.py" \
|
|
--code-file "$OUT_DIR/${iter_id}_generated_code.txt" \
|
|
--language "$LANGUAGE" \
|
|
"${strict_arg[@]}" \
|
|
--out "$fixed_gate" >/tmp/production_loop_gate_fix_${i}.json
|
|
log_trace "autofix" "$iter_id" "$(cat "$OUT_DIR/${iter_id}_fix_report.json")"
|
|
log_trace "gates_after_fix" "$iter_id" "$(cat "$fixed_gate")"
|
|
cp "$fixed_gate" "$OUT_DIR/${iter_id}_gates.json"
|
|
ready="$(jq -r '.gates.overall_ready' "$OUT_DIR/${iter_id}_gates.json")"
|
|
if [[ "$ready" == "true" ]]; then
|
|
status="green"
|
|
blocked_reason=""
|
|
final_ready=1
|
|
break
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Run same-language pipeline for diagnostics when compile/test fail.
|
|
code="$(cat "$OUT_DIR/${iter_id}_generated_code.txt")"
|
|
pipeline_args="$(jq -nc --arg src "$code" --arg lang "$LANGUAGE" '{source:$src,sourceLanguage:$lang,targetLanguage:$lang}')"
|
|
pipeline_raw="$(call_tool whetstone_run_pipeline "$pipeline_args")"
|
|
printf '%s\n' "$pipeline_raw" > "$OUT_DIR/${iter_id}_pipeline_raw.json"
|
|
pipeline_parsed="$(extract_json "$pipeline_raw")"
|
|
printf '%s\n' "$pipeline_parsed" > "$OUT_DIR/${iter_id}_pipeline.json"
|
|
log_trace "pipeline_diagnostics" "$iter_id" "$pipeline_parsed"
|
|
|
|
python3 "$ROOT_DIR/tools/mcp/remediation_router.py" \
|
|
--gates-json "$OUT_DIR/${iter_id}_gates.json" \
|
|
--out "$OUT_DIR/${iter_id}_route.json" >/tmp/production_loop_route_${i}.json
|
|
|
|
route_payload="$(cat "$OUT_DIR/${iter_id}_route.json")"
|
|
log_trace "route" "$iter_id" "$route_payload"
|
|
|
|
blocked="$(jq -r '.blocked' "$OUT_DIR/${iter_id}_route.json")"
|
|
if [[ "$blocked" == "true" ]]; then
|
|
status="blocked"
|
|
blocked_reason="$(jq -r '.blocked_reason' "$OUT_DIR/${iter_id}_route.json")"
|
|
break
|
|
fi
|
|
|
|
hints="$(jq -r '[.actions[].hint] | unique | join("\n")' "$OUT_DIR/${iter_id}_route.json")"
|
|
loop_spec="$loop_spec
|
|
|
|
Remediation directives (iteration $i):
|
|
$hints
|
|
|
|
Requirements:
|
|
- no TODO/FIXME/placeholder markers
|
|
- concrete field and method types
|
|
- compile-clean output for target language
|
|
- queue operations must be behaviorally complete: enqueue/dequeue/peek/size/empty"
|
|
done
|
|
|
|
if [[ "$status" == "green" ]]; then
|
|
blocked_reason=""
|
|
fi
|
|
|
|
jq -nc \
|
|
--arg out_dir "$OUT_DIR" \
|
|
--arg spec "$SPEC" \
|
|
--arg language "$LANGUAGE" \
|
|
--arg status "$status" \
|
|
--arg blocked_reason "$blocked_reason" \
|
|
--argjson strict_mode "$STRICT_MODE" \
|
|
--argjson max_iters "$MAX_ITERS" \
|
|
--argjson overall_ready "$final_ready" \
|
|
'{
|
|
out_dir:$out_dir,
|
|
spec:$spec,
|
|
language:$language,
|
|
strict_mode:($strict_mode==1),
|
|
max_iters:$max_iters,
|
|
overall_ready:($overall_ready==1),
|
|
status:$status,
|
|
blocked_reason:$blocked_reason
|
|
}' > "$OUT_DIR/00_summary.json"
|
|
|
|
echo "Production completion loop output: $OUT_DIR"
|
|
cat "$OUT_DIR/00_summary.json"
|