Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion scripts/play_party.sh
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@ MCURSOR="$(wc -l < "$MOVES" 2>/dev/null | tr -d ' ')"; MCURSOR="${MCURSOR:-0}"
# CLAWDND_PLAY_MAX_IDLE seconds (default 30 min) with no new move; relaunch when you're ready.
MAX_IDLE="${CLAWDND_PLAY_MAX_IDLE:-1800}"
last_activity=$SECONDS
# G1: drive the story arc per beat via the SHARED runbook (clawdnd_runbook_for_beat in
# lib_beat_driver.sh) — the SAME arc-driver run_duo.sh uses (which reaches combat/travel/rest).
# Without it the .app DM was purely reactive, so free-play personas finished at the intro and the
# full 8-beat arc (parley → engine combat → travel → rest → travel) never fired (G1 fail, 2026-06-03).
BEAT_NO=0; PREV_LOC=""
while true; do
over_budget && break
total="$(wc -l < "$MOVES" 2>/dev/null | tr -d ' ')"; total="${total:-0}"
Expand All @@ -591,6 +596,13 @@ while true; do
echo "[play-party] you: ${PMSG:0:100}"
chatlog player "$PMSG"

# G1 arc-driver: pick this beat's moment-specific runbook (scene-intro / midpoint reversal /
# climax / travel-peopling / rising-action) off the engine's progress, like run_duo.sh. Nominal
# 8-beat arc so the phases progress as the session builds. Injected into the DM turn below.
BEAT_NO=$((BEAT_NO + 1))
RUNBOOK="$(clawdnd_runbook_for_beat "$BEAT_NO" 8 "$PREV_LOC" "$STATE_DIR")"
echo "[play-party] beat $BEAT_NO runbook: ${RUNBOOK%% (*}…"

# Each living companion reacts to the LAST DM narration + (implicitly) the unfolding
# beat, taking its own move via its facade. Relay ONLY structured moves to the DM.
COMP_BLOCK="$(companion_moves "The DM says:
Expand All @@ -610,7 +622,9 @@ $PMSG${COMP_BLOCK:+

$COMP_BLOCK}"

DMSG="$(turn dm "$DSID" 0 "This beat, the party acts (resolve EACH actor's structured moves through the engine — roll/cast/attack/use as needed; a companion's [attack] on an ALLY is a real betrayal, resolve it as combat, do not soften it into narration):
DMSG="$(turn dm "$DSID" 0 "$RUNBOOK

This beat, the party acts (resolve EACH actor's structured moves through the engine — roll/cast/attack/use as needed; a companion's [attack] on an ALLY is a real betrayal, resolve it as combat, do not soften it into narration):

$PARTY_BLOCK

Expand All @@ -621,6 +635,8 @@ Then PLAY the next beat as a full lived scene — NOT a fragment: any NPC (or co
# player-facing narration the engine logged this beat so the chat is never blank.
DMSG="$(clawdnd_dm_narration_or_fallback "$DMSG" "$STATE_DIR")"
chatlog dm "$DMSG"; AGENT_TURNS=$((AGENT_TURNS + 1))
# Remember this beat's location so the next beat's runbook can detect a stuck party (travel cue).
PREV_LOC="$(printf '%s' "$(clawdnd_read_progress "$STATE_DIR")" | cut -f5)"
else
if [ $((SECONDS - last_activity)) -ge "$MAX_IDLE" ]; then
echo "[play-party] idle ${MAX_IDLE}s with no player move — stopping (relaunch when ready; raise CLAWDND_PLAY_MAX_IDLE to wait longer)."
Expand Down
11 changes: 11 additions & 0 deletions servers/engine/tests/test_dm_session_remint.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,14 @@ def test_play_party_single_flights_the_cold_open_campaign():
assert "Single-flight (#640)" in party, "play_party.sh lost the single-flight reuse"
assert "_minted = camp is None" in party, "must only mint when no recent campaign was reused"
assert "time.time() - os.path.getmtime" in party, "reuse must be scoped by a recency window (this run only)"


def test_play_party_drives_the_arc_runbook():
"""G1 (2026-06-03): the .app DM path (play_party.sh) must DRIVE the story arc per beat via the
shared clawdnd_runbook_for_beat (the same arc-driver run_duo.sh uses, which reaches engine
combat/travel/rest). Without it the DM was purely reactive and free-play personas finished at
the intro — the full 8-beat arc never fired (G1 fail). Mirrors play.sh/run_duo arc-driving."""
party = _src("scripts/play_party.sh")
assert "clawdnd_runbook_for_beat" in party, "play_party.sh must call the shared arc runbook"
assert "BEAT_NO=$((BEAT_NO + 1))" in party, "must advance a per-beat counter for the runbook"
assert 'turn dm "$DSID" 0 "$RUNBOOK' in party, "the runbook must be injected into the DM beat turn"
Loading