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
3 changes: 3 additions & 0 deletions inc/Tools/GitHubIssueTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ function ( $r ) {
'class' => __CLASS__,
'method' => 'handle_tool_call',
'description' => $description,
'runtime' => array(
'completion_signal' => 'progress',
),
'parameters' => array(
'type' => 'object',
'properties' => array(
Expand Down
3 changes: 3 additions & 0 deletions inc/Tools/GitHubPullRequestTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ function ( $r ) {
'class' => __CLASS__,
'method' => 'handle_tool_call',
'description' => $description,
'runtime' => array(
'completion_signal' => 'progress',
),
'parameters' => array(
'type' => 'object',
'properties' => array(
Expand Down
64 changes: 40 additions & 24 deletions inc/Tools/GitHubTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public function handleListIssues( array $parameters, array $tool_def = array() )
* @return array
*/
public function getListIssuesDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleListIssues',
'description' => 'List issues from a GitHub repository. Returns issue numbers, titles, states, labels, assignees, comment counts, timestamps, and a generated_at timestamp. Use to review open issues, track progress, or find specific issues by label.',
Expand All @@ -225,7 +225,7 @@ public function getListIssuesDefinition(): array {
),
'required' => array( 'repo' ),
),
);
) );
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -259,7 +259,7 @@ public function handleGetIssue( array $parameters, array $tool_def = array() ):
* @return array
*/
public function getGetIssueDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleGetIssue',
'description' => 'Get a single GitHub issue with full details including body, labels, assignees, comment count, timestamps, generated_at, and latest comment metadata when comments exist.',
Expand All @@ -277,7 +277,7 @@ public function getGetIssueDefinition(): array {
),
'required' => array( 'repo', 'issue_number' ),
),
);
) );
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -323,7 +323,7 @@ public function handleManageIssue( array $parameters, array $tool_def = array()
* @return array
*/
public function getManageIssueDefinition(): array {
return array(
return $this->progressDefinition( array(
'class' => __CLASS__,
'method' => 'handleManageIssue',
'description' => 'Update, close, or comment on a GitHub issue. Use action "update" to change title/body or replace the full labels set, "close" to close the issue, or "comment" to add a comment. For surgical label edits that preserve other labels, use add_label_to_issue or remove_label_from_issue instead - action=update replaces the full label set.',
Expand Down Expand Up @@ -362,7 +362,7 @@ public function getManageIssueDefinition(): array {
),
'required' => array( 'repo', 'issue_number', 'action' ),
),
);
) );
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -508,7 +508,7 @@ public function handleCommentPullRequest( array $parameters, array $tool_def = a
* @return array
*/
public function getCommentPullRequestDefinition(): array {
return array(
return $this->progressDefinition( array(
'class' => __CLASS__,
'method' => 'handleCommentPullRequest',
'description' => 'Comment on a GitHub pull request without granting broader issue update or close capabilities.',
Expand All @@ -534,7 +534,7 @@ public function getCommentPullRequestDefinition(): array {
),
'required' => array( 'repo', 'pull_number', 'body' ),
),
);
) );
}

/**
Expand Down Expand Up @@ -666,7 +666,7 @@ public function handleListPulls( array $parameters, array $tool_def = array() ):
* @return array
*/
public function getListPullsDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleListPulls',
'description' => 'List pull requests from a GitHub repository. Returns PR numbers, titles, states, branches, merge status, comment counts, change counts, timestamps, and generated_at.',
Expand All @@ -684,7 +684,7 @@ public function getListPullsDefinition(): array {
),
'required' => array( 'repo' ),
),
);
) );
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -737,7 +737,7 @@ public function handleGetPull( array $parameters ): array {
* @return array
*/
public function getGetPullDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleGetPull',
'description' => 'Get one GitHub pull request with normalized title, body, branch, SHA, labels, merge metadata, comment counts, change counts, timestamps, and generated_at.',
Expand All @@ -755,7 +755,7 @@ public function getGetPullDefinition(): array {
),
'required' => array( 'repo', 'pull_number' ),
),
);
) );
}

/**
Expand All @@ -774,7 +774,7 @@ public function handlePullFiles( array $parameters ): array {
* @return array
*/
public function getPullFilesDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handlePullFiles',
'description' => 'List files changed by a GitHub pull request, including filename, status, additions, deletions, and patch when available.',
Expand All @@ -800,7 +800,7 @@ public function getPullFilesDefinition(): array {
),
'required' => array( 'repo', 'pull_number' ),
),
);
) );
}

/**
Expand Down Expand Up @@ -1017,7 +1017,7 @@ public function handleRunPrHomeboyReview( array $parameters ): array {
* @return array
*/
public function getPullReviewContextDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handlePullReviewContext',
'description' => 'Build a review-ready context packet for a GitHub pull request, including normalized PR metadata and changed-file patches.',
Expand Down Expand Up @@ -1092,7 +1092,7 @@ public function getPullReviewContextDefinition(): array {
),
'required' => array( 'repo', 'pull_number' ),
),
);
) );
}

/**
Expand Down Expand Up @@ -1249,7 +1249,7 @@ public function handleListTree( array $parameters ): array {
* @return array
*/
public function getListTreeDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleListTree',
'description' => 'List files in a GitHub repository tree at a branch, tag, or commit SHA. Optionally filter to a path prefix.',
Expand All @@ -1271,7 +1271,7 @@ public function getListTreeDefinition(): array {
),
'required' => array( 'repo' ),
),
);
) );
}

/**
Expand All @@ -1290,7 +1290,7 @@ public function handleGetFile( array $parameters ): array {
* @return array
*/
public function getGetFileDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleGetFile',
'description' => 'Get decoded content for one or more files from a GitHub repository. Accepts path for one file or paths for one-or-many; always returns files[].',
Expand Down Expand Up @@ -1321,7 +1321,7 @@ public function getGetFileDefinition(): array {
),
'required' => array( 'repo' ),
),
);
) );
}

/**
Expand All @@ -1340,7 +1340,7 @@ public function handleCreateOrUpdateFile( array $parameters ): array {
* @return array
*/
public function getCreateOrUpdateFileDefinition(): array {
return array(
return $this->progressDefinition( array(
'class' => __CLASS__,
'method' => 'handleCreateOrUpdateFile',
'description' => 'Create or update a file in a GitHub repository using the Contents API. If branch is provided and does not exist, it is created from the repository default branch before committing.',
Expand Down Expand Up @@ -1375,7 +1375,7 @@ public function getCreateOrUpdateFileDefinition(): array {
),
'required' => array( 'repo', 'file_path', 'content', 'commit_message' ),
),
);
) );
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -1409,7 +1409,7 @@ public function handleListRepos( array $parameters, array $tool_def = array() ):
* @return array
*/
public function getListReposDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleListRepos',
'description' => 'List GitHub repositories for a user or organization. Shows repo names, languages, stars, open issues, and last push date.',
Expand All @@ -1427,6 +1427,22 @@ public function getListReposDefinition(): array {
),
'required' => array( 'owner' ),
),
);
) );
}

/** @param array<string,mixed> $definition Tool definition. @return array<string,mixed> */
private function repeatableDefinition( array $definition ): array {
return $this->withRuntime( $definition, array( 'duplicate_policy' => 'repeatable' ) );
}

/** @param array<string,mixed> $definition Tool definition. @return array<string,mixed> */
private function progressDefinition( array $definition ): array {
return $this->withRuntime( $definition, array( 'completion_signal' => 'progress' ) );
}

/** @param array<string,mixed> $definition Tool definition. @param array<string,mixed> $runtime Runtime metadata. @return array<string,mixed> */
private function withRuntime( array $definition, array $runtime ): array {
$definition['runtime'] = array_merge( is_array( $definition['runtime'] ?? null ) ? $definition['runtime'] : array(), $runtime );
return $definition;
}
}
18 changes: 12 additions & 6 deletions inc/Tools/WordPressRuntimeTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function getToolDefinition(): array {

/** @return array<string,mixed> */
public function getInventoryDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleInventory',
'description' => 'Inspect the live WordPress runtime inventory: WP/PHP versions, active theme, installed plugins/themes, mu-plugins, drop-ins, and safe source-root policy metadata.',
Expand All @@ -91,12 +91,12 @@ public function getInventoryDefinition(): array {
'properties' => array(),
'required' => array(),
),
);
) );
}

/** @return array<string,mixed> */
public function getLsDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleLs',
'description' => 'List files/directories under allowlisted WordPress runtime source roots only. Default path is wp-content/plugins.',
Expand All @@ -114,12 +114,12 @@ public function getLsDefinition(): array {
),
'required' => array(),
),
);
) );
}

/** @return array<string,mixed> */
public function getReadDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleRead',
'description' => 'Read a bounded text file under allowlisted WordPress runtime source roots only. Denies sensitive paths, traversal, oversized files, and binary files.',
Expand All @@ -145,7 +145,13 @@ public function getReadDefinition(): array {
),
'required' => array( 'path' ),
),
);
) );
}

/** @param array<string,mixed> $definition Tool definition. @return array<string,mixed> */
private function repeatableDefinition( array $definition ): array {
$definition['runtime'] = array_merge( is_array( $definition['runtime'] ?? null ) ? $definition['runtime'] : array(), array( 'duplicate_policy' => 'repeatable' ) );
return $definition;
}

/** @param array<string,mixed> $input Ability input. @return array<string,mixed> */
Expand Down
14 changes: 10 additions & 4 deletions inc/Tools/WorkspaceDiffTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function getToolDefinition(): array {

/** @return array<string,mixed> */
public function getDiffSummaryDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleDiffSummary',
'description' => 'Summarize changed files, additions/deletions, test-touch status, and compact git diff metadata for a workspace handle.',
Expand All @@ -74,12 +74,12 @@ public function getDiffSummaryDefinition(): array {
),
'required' => array( 'name' ),
),
);
) );
}

/** @return array<string,mixed> */
public function getDiffValidateDefinition(): array {
return array(
return $this->repeatableDefinition( array(
'class' => __CLASS__,
'method' => 'handleDiffValidate',
'description' => 'Validate workspace diff shape using allowed/denied path patterns and optional test-change requirements.',
Expand Down Expand Up @@ -109,7 +109,13 @@ public function getDiffValidateDefinition(): array {
),
'required' => array( 'name' ),
),
);
) );
}

/** @param array<string,mixed> $definition Tool definition. @return array<string,mixed> */
private function repeatableDefinition( array $definition ): array {
$definition['runtime'] = array_merge( is_array( $definition['runtime'] ?? null ) ? $definition['runtime'] : array(), array( 'duplicate_policy' => 'repeatable' ) );
return $definition;
}

/** @param array<string,mixed> $parameters Tool parameters. @return array<string,mixed> */
Expand Down
Loading