PluginProbe
ZIP AI – AI Website Builder & AI Agent (Beta) / 0.0.8
ZIP AI – AI Website Builder & AI Agent (Beta) v0.0.8
0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
zip-ai / inc / abilities / zipai / system / list-code-snippets.php

list-code-snippets.php in ZIP AI – AI Website Builder & AI Agent (Beta) 0.0.8, at inc/abilities/zipai/system/list-code-snippets.php

159 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * List Code Snippets — read-only discovery ability for ZIP AI's native snippet registry.
4 *
5 * Exists alongside `zipai/run-snippet` (ManageCodeSnippet) specifically to give the
6 * LLM an unambiguous, read-only entry point for answering questions like
7 * "how many snippets do I have?" — the LLM was reliably SKIPPING the manage tool
8 * because its id ("run-snippet") implied execution rather than listing, leading
9 * to hallucinated "0 snippets" answers even when the filesystem had several.
10 *
11 * This ability is a direct read of wp-content/zip-ai-snippets/manifest.php. It does
12 * not mutate state and requires no approval. Calling it is always safe.
13 *
14 * @since 0.0.5
15 * @package zip-ai
16 */
17
18 namespace ZipAI\MCP\Classes\Abilities\Zipai\System;
19
20 use ZipAI\MCP\Classes\Abilities\Abstract_Ability;
21 use ZipAI\MCP\Classes\Core\Tool_Types;
22 use ZipAI\MCP\Classes\Core\Response;
23 use ZipAI\MCP\Classes\Core\Snippet_Store;
24
25 if ( ! defined( 'ABSPATH' ) ) {
26 exit;
27 }
28
29 class ListCodeSnippets extends Abstract_Ability {
30
31 /**
32 * Flags this ability as non-destructive (read-only).
33 *
34 * @var bool
35 */
36 protected $is_destructive = false;
37
38 /**
39 * Configures the ability's id, label, description and metadata.
40 *
41 * @return void
42 */
43 public function configure() {
44 $this->id = 'zipai/list-snippets';
45 $this->label = 'List Code Snippets';
46 // Factual contract only. Instructional copy ("USE THIS FIRST",
47 // "Never report a snippet count without calling this tool first")
48 // belongs in the server prompts, not the schema description.
49 $this->description = 'Read-only enumeration of every snippet registered in ZIP AI\'s native registry (wp-content/zip-ai-snippets/manifest.php). '
50 . 'ZIP AI snippets are stored on the filesystem, NOT in any database table — DB queries (wp_snippets, wpcode posts, post_type=snippet, etc.) return zero. '
51 . 'Returns: { count, snippets: [{ slug, title, files, enabled, description, execution, conditions }] }. '
52 . 'To modify (create/update/enable/delete), use zipai/run-snippet.';
53 // Read surface, so it tracks the REST list route's capability rather
54 // than the write cap — an admin who cannot author snippets still needs
55 // to see what is running. See Snippet_Store::read_capability().
56 $this->capability = Snippet_Store::read_capability();
57 }
58
59 /**
60 * Returns the tool-type classification for this ability.
61 *
62 * @return string One of the Tool_Types constants.
63 */
64 public function get_tool_type() {
65 return Tool_Types::READ;
66 }
67
68 /**
69 * Returns the JSON Schema for this ability's input arguments.
70 *
71 * @return array<string,mixed> JSON Schema describing accepted arguments.
72 */
73 public function get_input_schema() {
74 return array(
75 'type' => 'object',
76 'properties' => new \stdClass(),
77 'additionalProperties' => false,
78 );
79 }
80
81 /**
82 * Returns the JSON Schema for this ability's response.
83 *
84 * @return array<string,mixed> JSON Schema describing the response shape.
85 */
86 public function get_output_schema() {
87 return array(
88 'type' => 'object',
89 'properties' => array(
90 'success' => array( 'type' => 'boolean' ),
91 'message' => array( 'type' => 'string' ),
92 'data' => array(
93 'type' => 'object',
94 'properties' => array(
95 'count' => array( 'type' => 'integer' ),
96 'snippets' => array(
97 'type' => 'array',
98 'items' => array(
99 'type' => 'object',
100 'properties' => array(
101 'slug' => array( 'type' => 'string' ),
102 'title' => array( 'type' => 'string' ),
103 'enabled' => array( 'type' => 'boolean' ),
104 'description' => array( 'type' => 'string' ),
105 'files' => array(
106 'type' => 'array',
107 'items' => array( 'type' => 'string' ),
108 ),
109 ),
110 ),
111 ),
112 ),
113 ),
114 ),
115 );
116 }
117
118 /**
119 * Enumerates every snippet registered in the native registry.
120 *
121 * @param array<string,mixed> $input Validated input arguments (unused).
122 * @return array<string,mixed> Standardized success response with the snippet list.
123 */
124 public function execute( $input = array() ) {
125 $manifest = Snippet_Store::load();
126 $snippets = array();
127
128 foreach ( $manifest as $slug => $meta ) {
129 if ( '_version' === $slug ) {
130 continue;
131 }
132 /**
133 * Narrowed type for `$meta_array`.
134 *
135 * @var array<string,mixed> $meta_array
136 */
137 $meta_array = is_array( $meta ) ? $meta : array();
138 $normalized = Snippet_Store::normalize_snippet( $meta_array );
139 $snippets[] = array(
140 'slug' => $slug,
141 'title' => $normalized['title'],
142 'files' => $normalized['files'],
143 'enabled' => (bool) $normalized['enabled'],
144 'description' => $normalized['description'],
145 'execution' => $normalized['execution'],
146 'conditions' => $normalized['conditions'],
147 );
148 }
149
150 return Response::success(
151 count( $snippets ) . ' snippets found.',
152 array(
153 'count' => count( $snippets ),
154 'snippets' => $snippets,
155 )
156 );
157 }
158 }
159