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
13 changes: 11 additions & 2 deletions bin/xstep
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ function showHelp(string $commandName = 'xstep'): void
echo "CORE OPTIONS:\n";
echo " --break=SPEC Set breakpoints (file.php:line or file.php:line:condition)\n";
echo " --steps=N Record N steps of variable evolution (JSON output)\n";
echo " --watch=EXPR Watch expression, only record steps when value changes\n";
echo " (can be specified multiple times)\n";
echo " --context=TEXT Add contextual description for AI analysis (JSON output)\n";
echo " --include-vendor=PATTERNS Include vendor packages in trace\n";
echo " --help, -h Show this help\n";
Expand Down Expand Up @@ -252,6 +254,7 @@ function parseBreakpoints(string $breakSpec, bool $isDockerCommand = false): arr
$replMode = $isRepl; // Default to REPL mode if called as xrepl
$context = null;
$maxSteps = null;
$watches = [];

for ($i = 1; $i < count($argv); $i++) {
$arg = $argv[$i];
Expand Down Expand Up @@ -296,6 +299,11 @@ function parseBreakpoints(string $breakSpec, bool $isDockerCommand = false): arr
continue;
}

if ($parseOptions && str_starts_with($arg, '--watch=')) {
$watches[] = substr($arg, 8);
continue;
}

if ($parseOptions && str_starts_with($arg, '--include-vendor=')) {
// This flag is passed directly to prepend_filter.php via auto_prepend_file
continue;
Expand Down Expand Up @@ -389,11 +397,12 @@ function parseBreakpoints(string $breakSpec, bool $isDockerCommand = false): arr
'traceOnly' => $traceOnly,
'jsonOutput' => $jsonOutput,
'context' => $context,
'maxSteps' => $maxSteps
'maxSteps' => $maxSteps,
'watches' => $watches,
], $jsonOutput);
} else {
// For legacy format, only pass command if it's not just the target script
$options = ['breakpointFile' => $breakpointFile, 'traceOnly' => $traceOnly, 'jsonOutput' => $jsonOutput, 'context' => $context, 'maxSteps' => $maxSteps];
$options = ['breakpointFile' => $breakpointFile, 'traceOnly' => $traceOnly, 'jsonOutput' => $jsonOutput, 'context' => $context, 'maxSteps' => $maxSteps, 'watches' => $watches];
if (count($command) > 1 || ($command[0] !== $targetScript)) {
$options['command'] = $command;
}
Expand Down
27 changes: 27 additions & 0 deletions docs/schemas/xstep.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,33 @@
"variables": {
"type": "object",
"description": "Variable values at breakpoint"
},
"watches": {
"type": "array",
"description": "Watch expression evaluation results (present when --watch is used)",
"items": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "The watched PHP expression"
},
"value": {
"type": "string",
"description": "Current evaluated value"
},
"previous": {
"type": ["string", "null"],
"description": "Previous value (null for initial step)"
},
"reason": {
"type": "string",
"enum": ["initial", "changed", "out_of_scope"],
"description": "Why this watch was recorded"
}
},
"required": ["expression", "value", "reason"]
}
}
},
"required": ["location", "variables"]
Expand Down
Loading