mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-20 11:19:56 +08:00
test: extract MODE_RE + optionsSignature into PTY runner exports
Refactor prep for the upcoming per-finding AskUserQuestion count test
across plan-{ceo,eng,design,devex}-review. Both new tests and the existing
mode-routing test need the same mode regex and the same option-list
fingerprint dedupe — pulling them into one source of truth in
test/helpers/claude-pty-runner.ts so a fifth mode (or a tweak to the
fingerprint shape) updates everywhere instead of drifting per-test.
Mechanical: no behavior change in the mode-routing test.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -284,6 +284,35 @@ export function parseNumberedOptions(
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The four /plan-ceo-review modes. Used by `skill-e2e-plan-ceo-mode-routing`
|
||||||
|
* to detect Step 0F mode-selection AskUserQuestions, and by the upcoming
|
||||||
|
* finding-count tests as a Step-0 boundary signal: an AUQ whose options
|
||||||
|
* match this regex IS the mode pick (the last Step-0 question for plan-ceo).
|
||||||
|
*
|
||||||
|
* Lifted out of the mode-routing test so multiple PTY tests can share one
|
||||||
|
* source of truth — when /plan-ceo-review adds a fifth mode, one regex updates
|
||||||
|
* everywhere instead of drifting per-test.
|
||||||
|
*/
|
||||||
|
export const MODE_RE = /HOLD SCOPE|SCOPE EXPANSION|SELECTIVE EXPANSION|SCOPE REDUCTION/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stable signature for a parsed numbered-option list — used by tests to detect
|
||||||
|
* "is this AUQ the same as the last poll, or has the agent advanced to a new
|
||||||
|
* one?" Joins each option as `${index}:${label}` after sorting by index.
|
||||||
|
*
|
||||||
|
* Defensive sort means the signature is order-independent at the input level,
|
||||||
|
* even though `parseNumberedOptions` already returns indices in ascending order.
|
||||||
|
*/
|
||||||
|
export function optionsSignature(
|
||||||
|
opts: Array<{ index: number; label: string }>,
|
||||||
|
): string {
|
||||||
|
return [...opts]
|
||||||
|
.sort((a, b) => a.index - b.index)
|
||||||
|
.map((o) => `${o.index}:${o.label}`)
|
||||||
|
.join('|');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pure classifier for the visible TTY buffer. Decides which outcome the
|
* Pure classifier for the visible TTY buffer. Decides which outcome the
|
||||||
* polling loop should return on this tick, or `null` to keep polling.
|
* polling loop should return on this tick, or `null` to keep polling.
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import {
|
|||||||
isPermissionDialogVisible,
|
isPermissionDialogVisible,
|
||||||
parseNumberedOptions,
|
parseNumberedOptions,
|
||||||
isPlanReadyVisible,
|
isPlanReadyVisible,
|
||||||
|
MODE_RE,
|
||||||
|
optionsSignature,
|
||||||
TAIL_SCAN_BYTES,
|
TAIL_SCAN_BYTES,
|
||||||
type ClaudePtySession,
|
type ClaudePtySession,
|
||||||
} from './helpers/claude-pty-runner';
|
} from './helpers/claude-pty-runner';
|
||||||
@@ -44,8 +46,6 @@ import {
|
|||||||
const shouldRun = !!process.env.EVALS && process.env.EVALS_TIER === 'periodic';
|
const shouldRun = !!process.env.EVALS && process.env.EVALS_TIER === 'periodic';
|
||||||
const describeE2E = shouldRun ? describe : describe.skip;
|
const describeE2E = shouldRun ? describe : describe.skip;
|
||||||
|
|
||||||
const MODE_RE = /HOLD SCOPE|SCOPE EXPANSION|SELECTIVE EXPANSION|SCOPE REDUCTION/i;
|
|
||||||
|
|
||||||
interface ModeCase {
|
interface ModeCase {
|
||||||
mode: 'HOLD SCOPE' | 'SCOPE EXPANSION';
|
mode: 'HOLD SCOPE' | 'SCOPE EXPANSION';
|
||||||
/** Regex applied to visible-since-mode-pick text. At least one must match. */
|
/** Regex applied to visible-since-mode-pick text. At least one must match. */
|
||||||
@@ -96,8 +96,8 @@ async function navigateToModeAskUserQuestion(
|
|||||||
|
|
||||||
// Has the rendered list changed since last poll? If not, we're seeing
|
// Has the rendered list changed since last poll? If not, we're seeing
|
||||||
// the same prompt and shouldn't double-press.
|
// the same prompt and shouldn't double-press.
|
||||||
const sig = opts.map(o => `${o.index}:${o.label}`).join('|');
|
const sig = optionsSignature(opts);
|
||||||
const lastSig = lastSeenList.map(o => `${o.index}:${o.label}`).join('|');
|
const lastSig = optionsSignature(lastSeenList);
|
||||||
if (sig === lastSig) continue;
|
if (sig === lastSig) continue;
|
||||||
lastSeenList = opts;
|
lastSeenList = opts;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user