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
48 changes: 40 additions & 8 deletions scripts/homeboy-dmc-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,34 @@
return array( 'status' => $status, 'stdout' => $stdout, 'stderr' => $stderr, 'failure' => $failure );
};

$decode_json_output = static function ( string $stdout ): mixed {
try {
return json_decode(trim($stdout), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $original_error) {
$lines = preg_split('/\R/', $stdout);
if ( false === $lines ) {
throw $original_error;
}
$diagnostic_found = false;
while ( array() !== $lines ) {
$line = array_shift($lines);
if ( '' === trim($line) ) {
continue;
}
if ( preg_match('/^(?:PHP )?(?:Deprecated|Warning|Notice):\s/', ltrim($line)) ) {
$diagnostic_found = true;
continue;
}
array_unshift($lines, $line);
break;
}
if ( ! $diagnostic_found ) {
throw $original_error;
}
return json_decode(trim(implode("\n", $lines)), true, 512, JSON_THROW_ON_ERROR);
}
};

$canonical_task_url = static function ( string $task_url ): string {
$task_url = trim($task_url);
$task_url = preg_split('/[?#]/', $task_url, 2)[0] ?? '';
Expand Down Expand Up @@ -210,7 +238,7 @@ static function ( array $matches ): string {
exit($identity_capture['status'] > 0 && $identity_capture['status'] < 256 ? $identity_capture['status'] : 1);
}
try {
$identity = json_decode($identity_capture['stdout'], true, 512, JSON_THROW_ON_ERROR);
$identity = $decode_json_output($identity_capture['stdout']);
} catch (Throwable $error) {
fwrite(STDERR, "DMC tracker-attachment preview returned invalid identity JSON.\n");
exit(1);
Expand Down Expand Up @@ -247,7 +275,7 @@ static function ( array $matches ): string {
fwrite(STDERR, $safety_capture['stderr']);
exit($safety_capture['status'] > 0 && $safety_capture['status'] < 256 ? $safety_capture['status'] : 1);
}
$safety = json_decode($safety_capture['stdout'], true);
$safety = $decode_json_output($safety_capture['stdout']);
if ( ! is_array($safety) || 'datamachine-code/worktree-safety/v1' !== ( $safety['schema'] ?? null ) || true !== ( $safety['fresh'] ?? null ) || false !== ( $safety['dirty'] ?? null ) ) {
fwrite(STDERR, "DMC tracker-attachment preview requires a fresh clean worktree.\n");
exit(1);
Expand Down Expand Up @@ -283,7 +311,7 @@ static function ( array $matches ): string {
exit($capture['status'] > 0 && $capture['status'] < 256 ? $capture['status'] : 1);
}
try {
$attached = json_decode($capture['stdout'], true, 512, JSON_THROW_ON_ERROR);
$attached = $decode_json_output($capture['stdout']);
} catch (Throwable $error) {
fwrite(STDERR, "DMC tracker attachment returned invalid JSON.\n");
exit(1);
Expand Down Expand Up @@ -331,7 +359,11 @@ static function ( array $matches ): string {
$stderr = $capture['stderr'];
$status = $capture['status'];
if ( 0 !== $status ) {
$overflow = json_decode($stdout, true);
try {
$overflow = $decode_json_output($stdout);
} catch (Throwable $error) {
$overflow = null;
}
if ( is_array($overflow) && 'worktree_task_candidates_overflow' === ( $overflow['error']['code'] ?? $overflow['code'] ?? null ) ) {
fwrite(STDERR, "DMC task worktree execution exceeded its complete candidate bound.\n");
} else {
Expand All @@ -340,7 +372,7 @@ static function ( array $matches ): string {
exit($status > 0 && $status < 256 ? $status : 1);
}
try {
$rows = json_decode($stdout, true, 512, JSON_THROW_ON_ERROR);
$rows = $decode_json_output($stdout);
} catch (Throwable $error) {
fwrite(STDERR, 'DMC task worktree projection returned invalid JSON: ' . $error->getMessage() . "\n");
exit(1);
Expand Down Expand Up @@ -421,7 +453,7 @@ static function ( array $matches ): string {
exit($status > 0 && $status < 256 ? $status : 1);
}
try {
$plan = json_decode($stdout, true, 512, JSON_THROW_ON_ERROR);
$plan = $decode_json_output($stdout);
} catch (Throwable $error) {
fwrite(STDERR, 'DMC worktree plan returned invalid JSON: ' . $error->getMessage() . "\n");
exit(1);
Expand Down Expand Up @@ -457,7 +489,7 @@ static function ( array $matches ): string {
exit(2);
}

$run_provider = static function ( string $provider_operation, string $provider_value, string $provider_base = '' ) use ( $provider, $workspace ): array {
$run_provider = static function ( string $provider_operation, string $provider_value, string $provider_base = '' ) use ( $provider, $workspace, $decode_json_output ): array {
$command = array( PHP_BINARY, $provider, $provider_operation, $workspace, $provider_value );
if ( '' !== $provider_base ) {
$command[] = $provider_base;
Expand All @@ -474,7 +506,7 @@ static function ( array $matches ): string {
if ( 0 !== $status ) {
throw new RuntimeException('DMC worktree provider failed: ' . trim($stderr), $status);
}
$payload = json_decode($stdout, true, 512, JSON_THROW_ON_ERROR);
$payload = $decode_json_output($stdout);
if ( ! is_array($payload) ) {
throw new RuntimeException('DMC worktree provider returned an invalid envelope.');
}
Expand Down
10 changes: 9 additions & 1 deletion tests/homeboy-dmc-provider.sh
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ one = run("one")
expected = [{"handle": "fixture@task-425", "path": os.environ["DMC_STATE"], "branch": "fix/425-resolve-task", "task_url": "https://github.com/Extra-Chill/wp-coding-agents/issues/425", "safety": {"dirty": False, "unpushed": False, "primary": False}}]
if one.returncode or json.loads(one.stdout) != expected:
raise SystemExit(f"FAIL: one task candidate did not retain its full identity: {one!r}")
diagnostic_prefix = run("diagnostic_prefix")
if diagnostic_prefix.returncode or json.loads(diagnostic_prefix.stdout) != expected:
raise SystemExit(f"FAIL: recognized PHP diagnostics must not contaminate typed task lookup JSON: {diagnostic_prefix!r}")
arbitrary_prefix = run("arbitrary_prefix")
if arbitrary_prefix.returncode == 0 or arbitrary_prefix.stdout or "invalid JSON" not in arbitrary_prefix.stderr:
raise SystemExit(f"FAIL: arbitrary task lookup prefixes must fail closed: {arbitrary_prefix!r}")
ambiguous = run("ambiguous")
if ambiguous.returncode or [item["handle"] for item in json.loads(ambiguous.stdout)] != ["fixture@task-425", "fixture@task-425-other"]:
raise SystemExit(f"FAIL: ambiguous task candidates must retain DMC's complete bounded set: {ambiguous!r}")
Expand Down Expand Up @@ -570,7 +576,7 @@ if [ "$1 $2 $3 $4 $5" = "wp datamachine-code workspace worktree list" ]; then
zero)
printf '{"success":true,"total":0,"returned":0,"next_cursor":null,"worktrees":[]}\n'
;;
one|ambiguous|canonical|mismatched_task|incomplete_safety|default_http|large_inventory)
one|diagnostic_prefix|arbitrary_prefix|ambiguous|canonical|mismatched_task|incomplete_safety|default_http|large_inventory)
task='https://github.com/Extra-Chill/wp-coding-agents/issues/425'
[ "${DMC_TASK_LOOKUP_MODE:-}" = mismatched_task ] && task='https://github.com/Extra-Chill/wp-coding-agents/issues/other'
[ "${DMC_TASK_LOOKUP_MODE:-}" = canonical ] && task='HTTPS://GITHUB.COM/Extra-Chill/WP-Coding-Agents/issues/425/?query=value#fragment'
Expand All @@ -581,6 +587,8 @@ if [ "$1 $2 $3 $4 $5" = "wp datamachine-code workspace worktree list" ]; then
i=1
while [ "$i" -le 5000 ]; do i=$((i + 1)); done
fi
[ "${DMC_TASK_LOOKUP_MODE:-}" = diagnostic_prefix ] && printf '\nDeprecated: Case statements followed by a semicolon are deprecated.\n'
[ "${DMC_TASK_LOOKUP_MODE:-}" = arbitrary_prefix ] && printf 'unexpected output\n'
printf '{"success":true,"total":%s,"returned":%s,"next_cursor":null,"worktrees":[{"handle":"fixture@task-425","path":"%s","branch":"fix/425-resolve-task","task_full":{"task_url":"%s"},"safety":%s}' "$( [ "${DMC_TASK_LOOKUP_MODE:-}" = ambiguous ] && printf 2 || printf 1 )" "$( [ "${DMC_TASK_LOOKUP_MODE:-}" = ambiguous ] && printf 2 || printf 1 )" "$DMC_STATE" "$task" "$safety"
if [ "${DMC_TASK_LOOKUP_MODE:-}" = ambiguous ]; then
printf ',{"handle":"fixture@task-425-other","path":"%s-other","branch":"fix/425-resolve-task","task_full":{"task_url":"%s"},"safety":{"dirty":false,"unpushed":false,"primary":false}}' "$DMC_STATE" "$task"
Expand Down
Loading