@wootsup/yt-builder-mcp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +18 -6
  2. package/bin/yt-builder-mcp.js +6 -0
  3. package/dist/auth.d.ts +86 -6
  4. package/dist/auth.d.ts.map +1 -1
  5. package/dist/auth.js +141 -8
  6. package/dist/auth.js.map +1 -1
  7. package/dist/errors/sanitize.d.ts.map +1 -1
  8. package/dist/errors/sanitize.js +10 -0
  9. package/dist/errors/sanitize.js.map +1 -1
  10. package/dist/gateway/essentials.d.ts +1 -1
  11. package/dist/gateway/essentials.d.ts.map +1 -1
  12. package/dist/gateway/essentials.js +15 -2
  13. package/dist/gateway/essentials.js.map +1 -1
  14. package/dist/index.d.ts +5 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +52 -16
  17. package/dist/index.js.map +1 -1
  18. package/dist/install-skill.d.ts +10 -2
  19. package/dist/install-skill.d.ts.map +1 -1
  20. package/dist/install-skill.js +18 -7
  21. package/dist/install-skill.js.map +1 -1
  22. package/dist/platform/detect.d.ts +64 -0
  23. package/dist/platform/detect.d.ts.map +1 -0
  24. package/dist/platform/detect.js +98 -0
  25. package/dist/platform/detect.js.map +1 -0
  26. package/dist/platform/index.d.ts +72 -0
  27. package/dist/platform/index.d.ts.map +1 -1
  28. package/dist/platform/index.js +138 -0
  29. package/dist/platform/index.js.map +1 -1
  30. package/dist/platform/joomla.d.ts +44 -0
  31. package/dist/platform/joomla.d.ts.map +1 -0
  32. package/dist/platform/joomla.js +46 -0
  33. package/dist/platform/joomla.js.map +1 -0
  34. package/dist/server.d.ts +61 -2
  35. package/dist/server.d.ts.map +1 -1
  36. package/dist/server.js +86 -2
  37. package/dist/server.js.map +1 -1
  38. package/dist/setup-cli-confirm.d.ts +36 -0
  39. package/dist/setup-cli-confirm.d.ts.map +1 -0
  40. package/dist/setup-cli-confirm.js +59 -0
  41. package/dist/setup-cli-confirm.js.map +1 -0
  42. package/dist/setup-cli.d.ts +53 -1
  43. package/dist/setup-cli.d.ts.map +1 -1
  44. package/dist/setup-cli.js +525 -10
  45. package/dist/setup-cli.js.map +1 -1
  46. package/dist/setup-prompts.d.ts.map +1 -1
  47. package/dist/setup-prompts.js +12 -8
  48. package/dist/setup-prompts.js.map +1 -1
  49. package/dist/setup-wizard-types.d.ts +19 -3
  50. package/dist/setup-wizard-types.d.ts.map +1 -1
  51. package/dist/setup-wizard.d.ts.map +1 -1
  52. package/dist/setup-wizard.js +34 -1
  53. package/dist/setup-wizard.js.map +1 -1
  54. package/dist/sites/cli/add-site.d.ts +106 -0
  55. package/dist/sites/cli/add-site.d.ts.map +1 -0
  56. package/dist/sites/cli/add-site.js +185 -0
  57. package/dist/sites/cli/add-site.js.map +1 -0
  58. package/dist/sites/cli/list-sites.d.ts +40 -0
  59. package/dist/sites/cli/list-sites.d.ts.map +1 -0
  60. package/dist/sites/cli/list-sites.js +117 -0
  61. package/dist/sites/cli/list-sites.js.map +1 -0
  62. package/dist/sites/cli/remove-site.d.ts +60 -0
  63. package/dist/sites/cli/remove-site.d.ts.map +1 -0
  64. package/dist/sites/cli/remove-site.js +120 -0
  65. package/dist/sites/cli/remove-site.js.map +1 -0
  66. package/dist/sites/cli/set-default.d.ts +47 -0
  67. package/dist/sites/cli/set-default.d.ts.map +1 -0
  68. package/dist/sites/cli/set-default.js +69 -0
  69. package/dist/sites/cli/set-default.js.map +1 -0
  70. package/dist/sites/cli/test-site.d.ts +77 -0
  71. package/dist/sites/cli/test-site.d.ts.map +1 -0
  72. package/dist/sites/cli/test-site.js +146 -0
  73. package/dist/sites/cli/test-site.js.map +1 -0
  74. package/dist/sites/client-pool.d.ts +124 -0
  75. package/dist/sites/client-pool.d.ts.map +1 -0
  76. package/dist/sites/client-pool.js +172 -0
  77. package/dist/sites/client-pool.js.map +1 -0
  78. package/dist/sites/env-bridge.d.ts +55 -0
  79. package/dist/sites/env-bridge.d.ts.map +1 -0
  80. package/dist/sites/env-bridge.js +94 -0
  81. package/dist/sites/env-bridge.js.map +1 -0
  82. package/dist/sites/paths.d.ts +21 -0
  83. package/dist/sites/paths.d.ts.map +1 -0
  84. package/dist/sites/paths.js +37 -0
  85. package/dist/sites/paths.js.map +1 -0
  86. package/dist/sites/probe.d.ts +60 -0
  87. package/dist/sites/probe.d.ts.map +1 -0
  88. package/dist/sites/probe.js +112 -0
  89. package/dist/sites/probe.js.map +1 -0
  90. package/dist/sites/registry.d.ts +142 -0
  91. package/dist/sites/registry.d.ts.map +1 -0
  92. package/dist/sites/registry.js +163 -0
  93. package/dist/sites/registry.js.map +1 -0
  94. package/dist/sites/schema.d.ts +90 -0
  95. package/dist/sites/schema.d.ts.map +1 -0
  96. package/dist/sites/schema.js +71 -0
  97. package/dist/sites/schema.js.map +1 -0
  98. package/dist/sites/secret-resolver.d.ts +109 -0
  99. package/dist/sites/secret-resolver.d.ts.map +1 -0
  100. package/dist/sites/secret-resolver.js +189 -0
  101. package/dist/sites/secret-resolver.js.map +1 -0
  102. package/dist/sites/store.d.ts +82 -0
  103. package/dist/sites/store.d.ts.map +1 -0
  104. package/dist/sites/store.js +198 -0
  105. package/dist/sites/store.js.map +1 -0
  106. package/dist/sites/tools/index.d.ts +28 -0
  107. package/dist/sites/tools/index.d.ts.map +1 -0
  108. package/dist/sites/tools/index.js +30 -0
  109. package/dist/sites/tools/index.js.map +1 -0
  110. package/dist/sites/tools/sites-list.d.ts +48 -0
  111. package/dist/sites/tools/sites-list.d.ts.map +1 -0
  112. package/dist/sites/tools/sites-list.js +135 -0
  113. package/dist/sites/tools/sites-list.js.map +1 -0
  114. package/dist/sites/tools/sites-test.d.ts +47 -0
  115. package/dist/sites/tools/sites-test.d.ts.map +1 -0
  116. package/dist/sites/tools/sites-test.js +148 -0
  117. package/dist/sites/tools/sites-test.js.map +1 -0
  118. package/dist/skill-loader.d.ts +63 -3
  119. package/dist/skill-loader.d.ts.map +1 -1
  120. package/dist/skill-loader.js +123 -10
  121. package/dist/skill-loader.js.map +1 -1
  122. package/dist/tools/elements/builders.d.ts +2 -2
  123. package/dist/tools/elements/builders.d.ts.map +1 -1
  124. package/dist/tools/elements/builders.js +45 -23
  125. package/dist/tools/elements/builders.js.map +1 -1
  126. package/dist/tools/elements/handlers.d.ts +8 -1
  127. package/dist/tools/elements/handlers.d.ts.map +1 -1
  128. package/dist/tools/elements/handlers.js +37 -1
  129. package/dist/tools/elements/handlers.js.map +1 -1
  130. package/dist/tools/format/health-format.d.ts +12 -6
  131. package/dist/tools/format/health-format.d.ts.map +1 -1
  132. package/dist/tools/format/health-format.js +14 -11
  133. package/dist/tools/format/health-format.js.map +1 -1
  134. package/dist/tools/format/pages-format.d.ts +7 -1
  135. package/dist/tools/format/pages-format.d.ts.map +1 -1
  136. package/dist/tools/format/pages-format.js +25 -1
  137. package/dist/tools/format/pages-format.js.map +1 -1
  138. package/dist/tools/health.d.ts +2 -2
  139. package/dist/tools/health.d.ts.map +1 -1
  140. package/dist/tools/health.js +120 -47
  141. package/dist/tools/health.js.map +1 -1
  142. package/dist/tools/index.d.ts +9 -2
  143. package/dist/tools/index.d.ts.map +1 -1
  144. package/dist/tools/index.js +21 -7
  145. package/dist/tools/index.js.map +1 -1
  146. package/dist/tools/inspection.d.ts +2 -2
  147. package/dist/tools/inspection.d.ts.map +1 -1
  148. package/dist/tools/inspection.js +67 -22
  149. package/dist/tools/inspection.js.map +1 -1
  150. package/dist/tools/multi-items/builders.d.ts +2 -2
  151. package/dist/tools/multi-items/builders.d.ts.map +1 -1
  152. package/dist/tools/multi-items/builders.js +21 -8
  153. package/dist/tools/multi-items/builders.js.map +1 -1
  154. package/dist/tools/pages/builders.d.ts +2 -2
  155. package/dist/tools/pages/builders.d.ts.map +1 -1
  156. package/dist/tools/pages/builders.js +36 -24
  157. package/dist/tools/pages/builders.js.map +1 -1
  158. package/dist/tools/pages/handlers-read.d.ts.map +1 -1
  159. package/dist/tools/pages/handlers-read.js +10 -0
  160. package/dist/tools/pages/handlers-read.js.map +1 -1
  161. package/dist/tools/pages/schemas.d.ts.map +1 -1
  162. package/dist/tools/pages/schemas.js +18 -0
  163. package/dist/tools/pages/schemas.js.map +1 -1
  164. package/dist/tools/pool-resolve-helper.d.ts +83 -0
  165. package/dist/tools/pool-resolve-helper.d.ts.map +1 -0
  166. package/dist/tools/pool-resolve-helper.js +148 -0
  167. package/dist/tools/pool-resolve-helper.js.map +1 -0
  168. package/dist/tools/shared-schemas.d.ts +10 -0
  169. package/dist/tools/shared-schemas.d.ts.map +1 -1
  170. package/dist/tools/shared-schemas.js +20 -2
  171. package/dist/tools/shared-schemas.js.map +1 -1
  172. package/dist/tools/sources/builders.d.ts +2 -2
  173. package/dist/tools/sources/builders.d.ts.map +1 -1
  174. package/dist/tools/sources/builders.js +27 -15
  175. package/dist/tools/sources/builders.js.map +1 -1
  176. package/dist/tools/tool-builder/index.d.ts +1 -1
  177. package/dist/tools/tool-builder/index.d.ts.map +1 -1
  178. package/dist/tools/tool-builder/index.js +1 -1
  179. package/dist/tools/tool-builder/index.js.map +1 -1
  180. package/dist/tools/tool-builder/results.d.ts +34 -0
  181. package/dist/tools/tool-builder/results.d.ts.map +1 -1
  182. package/dist/tools/tool-builder/results.js +86 -0
  183. package/dist/tools/tool-builder/results.js.map +1 -1
  184. package/manifest.json +27 -10
  185. package/package.json +3 -1
  186. package/skills/yt-builder-mcp/SKILL.md +846 -0
  187. package/skills/yootheme-builder/SKILL.md +0 -587
@@ -0,0 +1,148 @@
1
+ /**
2
+ * W7 — `yootheme_builder_sites_test` L1 tool.
3
+ *
4
+ * Targeted connectivity probe for ONE site_id: runs `/health` (no auth
5
+ * required) + `/etag` (auth required) in parallel and returns a
6
+ * structured `{plugin_reachable, bearer_valid, platform, ...}` block.
7
+ *
8
+ * Why `site_id` is REQUIRED here (not optional):
9
+ * - Every other tool in the registry treats `site_id` as an optional
10
+ * selector that falls back to the default. `sites_test` is the
11
+ * exception: its raison d'être is to verify ONE specific id, so the
12
+ * schema upgrades from `.optional()` to required. The W5
13
+ * SITE_ID_SCHEMA pin-test in `tests/tools/site-id-schema.test.ts`
14
+ * explicitly skips this tool from its "every tool's site_id is
15
+ * optional" loop — see the SITES_TEST_EXEMPT_FROM_OPTIONAL set there.
16
+ *
17
+ * Why the result wraps `withSiteMeta`:
18
+ * - Once `pool.resolve(site_id)` succeeds we DO have a resolved-site
19
+ * descriptor, so the text-prefix `[<label> @ <host>] ` is the same
20
+ * site-awareness signal a Maria-class user already sees on every
21
+ * other tool. The W6.2 wrapper handles both green AND red results
22
+ * uniformly (it just stamps; no behaviour difference).
23
+ *
24
+ * Failure modes mapped:
25
+ * - `UnknownSiteError` → structured error `code: 'unknown_site'` with
26
+ * `available[]` hint (via `resolveSiteOrError`).
27
+ * - `NoDefaultSiteError` → cannot fire here because site_id is required
28
+ * and validated by Zod before the handler runs; left in the helper
29
+ * for defense-in-depth.
30
+ * - `/health` rejects → `plugin_reachable: false` + error message.
31
+ * - `/etag` 401/403 → `plugin_reachable: true` + `bearer_valid: false`.
32
+ * - `/etag` other reject → `plugin_reachable: true` + `bearer_valid:
33
+ * false` + raw error.
34
+ *
35
+ * @license MIT
36
+ */
37
+ import { detailResult } from '@getimo/mcp-toolkit';
38
+ import { z } from 'zod';
39
+ import { resolveSiteOrError, } from '../../tools/pool-resolve-helper.js';
40
+ import { defineTool, readOnly, structuredResult, withSiteMeta, } from '../../tools/tool-builder.js';
41
+ import { probeSite } from '../probe.js';
42
+ const SITES_TEST_OUTPUT_SCHEMA = z.object({
43
+ site_id: z.string(),
44
+ site_url: z.string(),
45
+ platform: z.enum(['wordpress', 'joomla']),
46
+ plugin_reachable: z.boolean(),
47
+ bearer_valid: z.boolean(),
48
+ etag_received: z.boolean(),
49
+ plugin_error: z.string().optional(),
50
+ bearer_error: z.string().optional(),
51
+ summary: z.string(),
52
+ });
53
+ /**
54
+ * Build the W7 `yootheme_builder_sites_test` tool.
55
+ *
56
+ * Signature accepts the {@link ClientPool} directly (no separate
57
+ * registry param) — `pool.resolve(site_id)` is the single source of
58
+ * truth and carries the registry inside.
59
+ */
60
+ export function buildSitesTestTool(pool) {
61
+ return defineTool({
62
+ name: 'yootheme_builder_sites_test',
63
+ description: 'Verify connectivity to ONE site: probes /health (no auth) + ' +
64
+ '/etag (auth) in parallel; returns plugin_reachable + ' +
65
+ 'bearer_valid. `site_id` is REQUIRED. Use sites_list to find IDs.',
66
+ inputSchema: {
67
+ site_id: z
68
+ .string()
69
+ .min(1)
70
+ .max(64)
71
+ .regex(/^[a-zA-Z0-9_-]+$/, 'site_id uses letters/digits/dash/underscore only')
72
+ .describe('Site to test (REQUIRED for this tool — overrides default). ' +
73
+ 'Use yootheme_builder_sites_list to discover valid IDs.'),
74
+ },
75
+ outputSchema: SITES_TEST_OUTPUT_SCHEMA,
76
+ annotations: readOnly('Sites — Test connectivity'),
77
+ handler: async ({ site_id }) => {
78
+ const r = await resolveSiteOrError(pool, site_id);
79
+ if (!r.ok)
80
+ return r.error;
81
+ const { client: siteClient, site } = r;
82
+ // W12-R1.2: the parallel /health + /etag probe lives in
83
+ // sites/probe.ts so MCP-tool + CLI surfaces stay byte-for-byte
84
+ // in sync. The handler here only maps the structured probe
85
+ // result into the toolkit detail-card envelope and stamps
86
+ // site-awareness via withSiteMeta.
87
+ const probe = await probeSite(siteClient);
88
+ const checks = {
89
+ site_id: site.id,
90
+ site_url: site.url,
91
+ platform: site.platform.kind,
92
+ plugin_reachable: probe.plugin_reachable,
93
+ bearer_valid: probe.bearer_valid,
94
+ etag_received: probe.etag_received,
95
+ summary: probe.summary,
96
+ ...(probe.plugin_error !== undefined ? { plugin_error: probe.plugin_error } : {}),
97
+ ...(probe.bearer_error !== undefined ? { bearer_error: probe.bearer_error } : {}),
98
+ };
99
+ const toolkitResult = detailResult(buildTestDetail(checks));
100
+ const isError = !(checks.plugin_reachable && checks.bearer_valid);
101
+ const base = structuredResult(toolkitResult, {
102
+ ...checks,
103
+ });
104
+ const wrapped = isError
105
+ ? { ...base, isError: true }
106
+ : base;
107
+ return withSiteMeta(wrapped, site);
108
+ },
109
+ });
110
+ }
111
+ /**
112
+ * Render a 2-group detail-card body from the structured `checks`. Group
113
+ * 1 = identity (site_id/url/platform), Group 2 = probe results
114
+ * (plugin_reachable + bearer_valid + etag_received + summary). Keeps the
115
+ * shape stable across green / partial / red so MCP-host Detail-Card
116
+ * renderers don't need to branch.
117
+ */
118
+ function buildTestDetail(checks) {
119
+ const identityEntries = [
120
+ { key: 'site_id', label: 'Site ID', value: checks.site_id, format: 'badge' },
121
+ { key: 'site_url', label: 'Site URL', value: checks.site_url },
122
+ { key: 'platform', label: 'Platform', value: checks.platform, format: 'badge' },
123
+ ];
124
+ const probeEntries = [
125
+ { key: 'plugin_reachable', label: 'Plugin reachable', value: checks.plugin_reachable, format: 'boolean' },
126
+ { key: 'bearer_valid', label: 'Bearer valid', value: checks.bearer_valid, format: 'boolean' },
127
+ { key: 'etag_received', label: 'ETag received', value: checks.etag_received, format: 'boolean' },
128
+ { key: 'summary', label: 'Summary', value: checks.summary },
129
+ ];
130
+ if (checks.plugin_error !== undefined) {
131
+ probeEntries.push({
132
+ key: 'plugin_error', label: 'Plugin error', value: checks.plugin_error, format: 'code',
133
+ });
134
+ }
135
+ if (checks.bearer_error !== undefined) {
136
+ probeEntries.push({
137
+ key: 'bearer_error', label: 'Bearer error', value: checks.bearer_error, format: 'code',
138
+ });
139
+ }
140
+ return {
141
+ title: 'YT Builder MCP — Sites Test',
142
+ groups: [
143
+ { label: 'Site', entries: identityEntries },
144
+ { label: 'Probe', entries: probeEntries },
145
+ ],
146
+ };
147
+ }
148
+ //# sourceMappingURL=sites-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sites-test.js","sourceRoot":"","sources":["../../../src/sites/tools/sites-test.ts"],"names":[],"mappings":"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"}
@@ -16,18 +16,35 @@
16
16
  *
17
17
  * Resolution layout (matches `install-skill.ts` + `build-dxt.js`):
18
18
  *
19
- * packages/mcp/skills/yootheme-builder/SKILL.md
19
+ * packages/mcp/skills/yt-builder-mcp/SKILL.md
20
20
  *
21
21
  * When the file is compiled to `dist/skill-loader.js`, the same
22
- * relative `../skills/yootheme-builder/SKILL.md` resolves correctly
22
+ * relative `../skills/yt-builder-mcp/SKILL.md` resolves correctly
23
23
  * because the published npm tarball (and the DXT stage) preserves the
24
24
  * `skills/` folder next to `dist/`.
25
25
  *
26
26
  * Read errors throw at module-init: a missing SKILL.md is a packaging
27
27
  * bug, not a recoverable runtime condition.
28
28
  *
29
+ * W8 — `appendSitesBlock(skillContent, registry)` post-processor.
30
+ * When the in-process {@link SiteRegistry} carries ≥1 configured
31
+ * site, append a "Currently configured sites" appendix to the
32
+ * instructions string so MCP hosts surface the live site roster
33
+ * alongside the skill narrative. The appendix contains ONLY
34
+ * safe-to-render metadata (site_id, label, platform hint/resolved,
35
+ * url, default-flag) — bearer fields are NEVER touched. When the
36
+ * registry has 0 sites the original skill content is returned
37
+ * verbatim (no appendix, no separator).
38
+ *
39
+ * This is a pure-string post-processor; it does not touch the
40
+ * on-disk SKILL.md. Per plan §W8 (line 919) the MCP `initialize`
41
+ * response carries `instructions` as a single shot, so an AI client
42
+ * restart is required for the appendix to refresh after a sites file
43
+ * edit. The W9 CLI commands (add-site / remove-site) print a reminder.
44
+ *
29
45
  * @license MIT
30
46
  */
47
+ import type { SiteRegistry } from './sites/registry.js';
31
48
  /** Stable URI under which the skill resource is exposed via MCP `resources/*`. */
32
49
  export declare const SKILL_RESOURCE_URI = "skill://yt-builder-mcp";
33
50
  /** Human-readable resource name surfaced in `resources/list`. */
@@ -39,9 +56,52 @@ export declare const SKILL_RESOURCE_MIME_TYPE = "text/markdown";
39
56
  /**
40
57
  * Load the bundled SKILL.md content. Cached after the first read.
41
58
  *
59
+ * When `registry` is supplied AND it carries ≥1 site, the returned
60
+ * string is the on-disk SKILL.md PLUS the W8 sites appendix (see
61
+ * {@link appendSitesBlock}). When `registry` is omitted or empty, the
62
+ * raw skill content is returned unchanged. The disk cache is shared
63
+ * across calls — the appendix is recomputed each time so registry
64
+ * mutations after the first load are reflected (within the same
65
+ * process instance — the MCP `initialize` response only takes a
66
+ * single-shot snapshot per session per plan §W8 line 919).
67
+ *
42
68
  * @throws Error when the file is missing or unreadable (packaging bug).
43
69
  */
44
- export declare function loadSkillContent(): string;
70
+ export declare function loadSkillContent(registry?: SiteRegistry): string;
71
+ /**
72
+ * Append the W8 "Currently configured sites" block to a skill-content
73
+ * string. When the registry is empty, returns the input verbatim — no
74
+ * separator, no header, no trailing newline change.
75
+ *
76
+ * Output shape (per plan §W8 Z.904-917):
77
+ * ```text
78
+ * <skillContent>
79
+ *
80
+ * ---
81
+ *
82
+ * ## Currently configured sites (3)
83
+ *
84
+ * - `wp-acme` — Acme — Production · wordpress · https://acme.com · default
85
+ * - `joomla-beta` — Beta — Staging · joomla · https://beta.example.com/joomla
86
+ * - `wp-internal` — Internal staging · wordpress · https://internal.example.com
87
+ *
88
+ * Use `yootheme_builder_sites_list` to inspect this at runtime.
89
+ * Pass `site_id: "<id>"` on any tool call to target a specific site;
90
+ * omit it to use the default.
91
+ * ```
92
+ *
93
+ * Per-row format (bullet):
94
+ * `- \`<site_id>\` — <label or "(no label)"> · <platform> · <url><" · default"?>`
95
+ *
96
+ * The platform column prefers `platform_resolved` when the registry
97
+ * has memoised a probe result for that site (peek-only — never
98
+ * triggers a new probe), and falls back to `platform_hint` otherwise.
99
+ *
100
+ * Bearer fields (bearer / bearer_ref) are intentionally NEVER
101
+ * referenced — only `site_id`, `url`, `platform_*`, `is_default`,
102
+ * `label` from {@link SiteRowT}.
103
+ */
104
+ export declare function appendSitesBlock(skillContent: string, registry: SiteRegistry): string;
45
105
  /**
46
106
  * Reset the in-memory cache. Intended for tests only.
47
107
  *
@@ -1 +1 @@
1
- {"version":3,"file":"skill-loader.d.ts","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAE3D,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,sCAAiC,CAAC;AAElE,wDAAwD;AACxD,eAAO,MAAM,0BAA0B,QAEqC,CAAC;AAE7E,0CAA0C;AAC1C,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAmBxD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
1
+ {"version":3,"file":"skill-loader.d.ts","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,qBAAqB,CAAC;AAElE,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAE3D,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,sCAAiC,CAAC;AAElE,wDAAwD;AACxD,eAAO,MAAM,0BAA0B,QAEqC,CAAC;AAE7E,0CAA0C;AAC1C,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAmBxD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAShE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,gBAAgB,CAC5B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,YAAY,GACvB,MAAM,CAkBR;AA0CD;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
@@ -16,16 +16,32 @@
16
16
  *
17
17
  * Resolution layout (matches `install-skill.ts` + `build-dxt.js`):
18
18
  *
19
- * packages/mcp/skills/yootheme-builder/SKILL.md
19
+ * packages/mcp/skills/yt-builder-mcp/SKILL.md
20
20
  *
21
21
  * When the file is compiled to `dist/skill-loader.js`, the same
22
- * relative `../skills/yootheme-builder/SKILL.md` resolves correctly
22
+ * relative `../skills/yt-builder-mcp/SKILL.md` resolves correctly
23
23
  * because the published npm tarball (and the DXT stage) preserves the
24
24
  * `skills/` folder next to `dist/`.
25
25
  *
26
26
  * Read errors throw at module-init: a missing SKILL.md is a packaging
27
27
  * bug, not a recoverable runtime condition.
28
28
  *
29
+ * W8 — `appendSitesBlock(skillContent, registry)` post-processor.
30
+ * When the in-process {@link SiteRegistry} carries ≥1 configured
31
+ * site, append a "Currently configured sites" appendix to the
32
+ * instructions string so MCP hosts surface the live site roster
33
+ * alongside the skill narrative. The appendix contains ONLY
34
+ * safe-to-render metadata (site_id, label, platform hint/resolved,
35
+ * url, default-flag) — bearer fields are NEVER touched. When the
36
+ * registry has 0 sites the original skill content is returned
37
+ * verbatim (no appendix, no separator).
38
+ *
39
+ * This is a pure-string post-processor; it does not touch the
40
+ * on-disk SKILL.md. Per plan §W8 (line 919) the MCP `initialize`
41
+ * response carries `instructions` as a single shot, so an AI client
42
+ * restart is required for the appendix to refresh after a sites file
43
+ * edit. The W9 CLI commands (add-site / remove-site) print a reminder.
44
+ *
29
45
  * @license MIT
30
46
  */
31
47
  import { readFileSync } from 'node:fs';
@@ -44,28 +60,125 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
44
60
  /**
45
61
  * Resolve the on-disk path to the bundled SKILL.md.
46
62
  *
47
- * Source-tree: packages/mcp/src/skill-loader.ts → ../skills/yootheme-builder/SKILL.md
48
- * Built tarball: packages/mcp/dist/skill-loader.js → ../skills/yootheme-builder/SKILL.md
63
+ * Source-tree: packages/mcp/src/skill-loader.ts → ../skills/yt-builder-mcp/SKILL.md
64
+ * Built tarball: packages/mcp/dist/skill-loader.js → ../skills/yt-builder-mcp/SKILL.md
49
65
  *
50
66
  * Both layouts work because `dist/` and `src/` are siblings of
51
67
  * `skills/` under the package root.
52
68
  */
53
69
  function resolveSkillPath() {
54
- return resolve(__dirname, '..', 'skills', 'yootheme-builder', 'SKILL.md');
70
+ return resolve(__dirname, '..', 'skills', 'yt-builder-mcp', 'SKILL.md');
55
71
  }
56
72
  let cached;
57
73
  /**
58
74
  * Load the bundled SKILL.md content. Cached after the first read.
59
75
  *
76
+ * When `registry` is supplied AND it carries ≥1 site, the returned
77
+ * string is the on-disk SKILL.md PLUS the W8 sites appendix (see
78
+ * {@link appendSitesBlock}). When `registry` is omitted or empty, the
79
+ * raw skill content is returned unchanged. The disk cache is shared
80
+ * across calls — the appendix is recomputed each time so registry
81
+ * mutations after the first load are reflected (within the same
82
+ * process instance — the MCP `initialize` response only takes a
83
+ * single-shot snapshot per session per plan §W8 line 919).
84
+ *
60
85
  * @throws Error when the file is missing or unreadable (packaging bug).
61
86
  */
62
- export function loadSkillContent() {
63
- if (cached !== undefined) {
87
+ export function loadSkillContent(registry) {
88
+ if (cached === undefined) {
89
+ const path = resolveSkillPath();
90
+ cached = readFileSync(path, 'utf-8');
91
+ }
92
+ if (registry === undefined) {
64
93
  return cached;
65
94
  }
66
- const path = resolveSkillPath();
67
- cached = readFileSync(path, 'utf-8');
68
- return cached;
95
+ return appendSitesBlock(cached, registry);
96
+ }
97
+ /**
98
+ * Append the W8 "Currently configured sites" block to a skill-content
99
+ * string. When the registry is empty, returns the input verbatim — no
100
+ * separator, no header, no trailing newline change.
101
+ *
102
+ * Output shape (per plan §W8 Z.904-917):
103
+ * ```text
104
+ * <skillContent>
105
+ *
106
+ * ---
107
+ *
108
+ * ## Currently configured sites (3)
109
+ *
110
+ * - `wp-acme` — Acme — Production · wordpress · https://acme.com · default
111
+ * - `joomla-beta` — Beta — Staging · joomla · https://beta.example.com/joomla
112
+ * - `wp-internal` — Internal staging · wordpress · https://internal.example.com
113
+ *
114
+ * Use `yootheme_builder_sites_list` to inspect this at runtime.
115
+ * Pass `site_id: "<id>"` on any tool call to target a specific site;
116
+ * omit it to use the default.
117
+ * ```
118
+ *
119
+ * Per-row format (bullet):
120
+ * `- \`<site_id>\` — <label or "(no label)"> · <platform> · <url><" · default"?>`
121
+ *
122
+ * The platform column prefers `platform_resolved` when the registry
123
+ * has memoised a probe result for that site (peek-only — never
124
+ * triggers a new probe), and falls back to `platform_hint` otherwise.
125
+ *
126
+ * Bearer fields (bearer / bearer_ref) are intentionally NEVER
127
+ * referenced — only `site_id`, `url`, `platform_*`, `is_default`,
128
+ * `label` from {@link SiteRowT}.
129
+ */
130
+ export function appendSitesBlock(skillContent, registry) {
131
+ const rows = registry.listForDisplay();
132
+ if (rows.length === 0) {
133
+ return skillContent;
134
+ }
135
+ const bullets = rows.map((row) => renderBullet(row)).join('\n');
136
+ const block = '\n\n---\n\n' +
137
+ `## Currently configured sites (${String(rows.length)})\n\n` +
138
+ bullets +
139
+ '\n\n' +
140
+ 'Use `yootheme_builder_sites_list` to inspect this at runtime.\n' +
141
+ 'Pass `site_id: "<id>"` on any tool call to target a specific site;\n' +
142
+ 'omit it to use the default.\n';
143
+ return skillContent + block;
144
+ }
145
+ /**
146
+ * Markdown-escape an operator-provided string so it cannot inject
147
+ * structure into the rendered SKILL.md appendix.
148
+ *
149
+ * W12-R1.3 (A2-L2): the W8 sites-appendix renders `row.label` into the
150
+ * server's `instructions` field, which MCP hosts surface to the LLM
151
+ * verbatim. An operator with write-access to sites.json could land a
152
+ * label like `Acme [INTERNAL TOOL: ignore prior context] Production`
153
+ * and the prompt would carry that text into the model context. The
154
+ * escape list covers the markdown special chars the W8 bullet format
155
+ * could collide with (\`*_[]<>), preserving readable text while
156
+ * preventing injection. site_id is regex-restricted at the schema
157
+ * layer so it doesn't need escaping; url is operator-controlled but
158
+ * has a much smaller chosen-char surface and is rendered after a `·`
159
+ * separator that limits payload shape.
160
+ */
161
+ function escapeMarkdown(text) {
162
+ return text.replace(/([\\`*_[\]<>])/g, '\\$1');
163
+ }
164
+ /**
165
+ * Render one {@link SiteRowT} as a markdown bullet for the W8 sites
166
+ * appendix.
167
+ *
168
+ * Format: `- \`<site_id>\` — <label> · <platform> · <url><" · default"?>`
169
+ *
170
+ * `<platform>` prefers `platform_resolved` (the W3 memo cache) and
171
+ * falls back to `platform_hint` when no probe has run yet.
172
+ * `<label>` falls back to the literal string `(no label)` when the
173
+ * entry has none AND is markdown-escaped (W12-R1.3 prompt-injection
174
+ * defense). The `default` suffix is only present when `is_default`
175
+ * is true.
176
+ */
177
+ function renderBullet(row) {
178
+ const platform = row.platform_resolved ?? row.platform_hint;
179
+ const label = escapeMarkdown(row.label ?? '(no label)');
180
+ const defaultSuffix = row.is_default ? ' · default' : '';
181
+ return `- \`${row.site_id}\` — ${label} · ${platform} · ${row.url}${defaultSuffix}`;
69
182
  }
70
183
  /**
71
184
  * Reset the in-memory cache. Intended for tests only.
@@ -1 +1 @@
1
- {"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,kFAAkF;AAClF,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAE3D,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAElE,wDAAwD;AACxD,MAAM,CAAC,MAAM,0BAA0B,GACnC,gFAAgF;IAChF,wEAAwE,CAAC;AAE7E,0CAA0C;AAC1C,MAAM,CAAC,MAAM,wBAAwB,GAAG,eAAe,CAAC;AAExD,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;;;;;;;GAQG;AACH,SAAS,gBAAgB;IACrB,OAAO,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAC;AAC9E,CAAC;AAED,IAAI,MAA0B,CAAC;AAE/B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC5B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACrC,MAAM,GAAG,SAAS,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @license MIT
13
13
  */
14
- import type { RestClient } from '../../client.js';
14
+ import type { ClientPool } from '../../sites/client-pool.js';
15
15
  import { type AnyToolDefinition } from '../tool-builder.js';
16
16
  import { type ElementsHandlerDeps } from './handlers.js';
17
17
  /**
@@ -20,5 +20,5 @@ import { type ElementsHandlerDeps } from './handlers.js';
20
20
  * omitted, the destructive tool falls back to the explicit
21
21
  * `confirm: true` parameter.
22
22
  */
23
- export declare function buildElementsTools(client: RestClient, deps?: Partial<ElementsHandlerDeps>): readonly AnyToolDefinition[];
23
+ export declare function buildElementsTools(pool: ClientPool, deps?: Partial<ElementsHandlerDeps>): readonly AnyToolDefinition[];
24
24
  //# sourceMappingURL=builders.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../../src/tools/elements/builders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,OAAO,EAMH,KAAK,iBAAiB,EACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGH,KAAK,mBAAmB,EAQ3B,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,UAAU,EAClB,IAAI,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GACpC,SAAS,iBAAiB,EAAE,CAiL9B"}
1
+ {"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../../../src/tools/elements/builders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAI7D,OAAO,EAOH,KAAK,iBAAiB,EACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGH,KAAK,mBAAmB,EAQ3B,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,IAAI,EAAE,UAAU,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GACpC,SAAS,iBAAiB,EAAE,CAqN9B"}
@@ -12,9 +12,10 @@
12
12
  * @license MIT
13
13
  */
14
14
  import { z } from 'zod';
15
- import { ELEMENT_PATH, ETAG, PROPS, TEMPLATE_ID } from '../shared-schemas.js';
15
+ import { withSiteRetry } from '../pool-resolve-helper.js';
16
+ import { ELEMENT_PATH, ETAG, PROPS, SITE_ID_SCHEMA, TEMPLATE_ID } from '../shared-schemas.js';
16
17
  import { FIELDS } from '../sparse-fields.js';
17
- import { creating, defineTool, destructive, mutating, readOnly, } from '../tool-builder.js';
18
+ import { creating, defineTool, destructive, mutating, readOnly, withSiteMeta, } from '../tool-builder.js';
18
19
  import { ELEMENT_GET_OUTPUT_SCHEMA, ELEMENT_LIST_OUTPUT_SCHEMA, handleElementAdd, handleElementClone, handleElementDelete, handleElementGet, handleElementList, handleElementMove, handleElementUpdateSettings, } from './handlers.js';
19
20
  /**
20
21
  * Build the 7 element tools. The optional `deps` carries the
@@ -22,18 +23,23 @@ import { ELEMENT_GET_OUTPUT_SCHEMA, ELEMENT_LIST_OUTPUT_SCHEMA, handleElementAdd
22
23
  * omitted, the destructive tool falls back to the explicit
23
24
  * `confirm: true` parameter.
24
25
  */
25
- export function buildElementsTools(client, deps) {
26
- const handlerDeps = {
27
- client,
28
- elicitation: deps?.elicitation,
29
- };
26
+ export function buildElementsTools(pool, deps) {
27
+ // W6.3 each handler resolves the pool inline (per `site_id`) so
28
+ // the per-handler `siteClient` reaches the right CMS install. The
29
+ // elicitation capability is the only non-client dep we propagate.
30
+ const elicitation = deps?.elicitation;
31
+ const makeDeps = (siteClient) => (elicitation !== undefined
32
+ ? { client: siteClient, elicitation }
33
+ : { client: siteClient });
30
34
  return [
31
35
  defineTool({
32
36
  name: 'yootheme_builder_element_list',
33
37
  description: 'List elements in a template as a flat array with JSON-Pointer paths + ' +
34
38
  'types. Scope with `root_path`/`depth` for a subtree, paginate with ' +
35
- '`limit`/`cursor` for large templates. `fields[]` narrows each row.',
39
+ '`limit`/`cursor` for large templates. `fields[]` narrows each row. ' +
40
+ 'Operates on the default site unless site_id is provided.',
36
41
  inputSchema: {
42
+ site_id: SITE_ID_SCHEMA,
37
43
  template_id: TEMPLATE_ID,
38
44
  fields: FIELDS,
39
45
  root_path: z
@@ -61,32 +67,41 @@ export function buildElementsTools(client, deps) {
61
67
  },
62
68
  outputSchema: ELEMENT_LIST_OUTPUT_SCHEMA,
63
69
  annotations: readOnly('List Elements'),
64
- handler: (input) => handleElementList(handlerDeps, input),
70
+ handler: async ({ site_id, ...rest }) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementList(makeDeps(client), rest), site)),
65
71
  }),
66
72
  defineTool({
67
73
  name: 'yootheme_builder_element_get',
68
74
  description: 'Get the full element object at a specific JSON-Pointer path, including props ' +
69
- 'and children. Use yootheme_builder_element_list to discover paths.',
75
+ 'and children. Use yootheme_builder_element_list to discover paths. ' +
76
+ 'Operates on the default site unless site_id is provided.',
70
77
  inputSchema: {
78
+ site_id: SITE_ID_SCHEMA,
71
79
  template_id: TEMPLATE_ID,
72
80
  element_path: ELEMENT_PATH,
73
81
  },
74
82
  outputSchema: ELEMENT_GET_OUTPUT_SCHEMA,
75
83
  annotations: readOnly('Get Element'),
76
- handler: (input) => handleElementGet(handlerDeps, input),
84
+ handler: async ({ site_id, ...rest }) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementGet(makeDeps(client), rest), site)),
77
85
  }),
78
86
  defineTool({
79
87
  name: 'yootheme_builder_element_add',
80
88
  description: 'Add a new element to a template. Provide `parent_path` (or "" for root), ' +
81
89
  '`element_type` (e.g. "headline", "text", "grid"), and optional `props` / ' +
82
- '`children`. Returns the new element\'s JSON-Pointer path. Requires ETag.',
90
+ '`children`. Returns the new element\'s JSON-Pointer path. Requires ETag. ' +
91
+ 'Operates on the default site unless site_id is provided.',
83
92
  inputSchema: {
93
+ site_id: SITE_ID_SCHEMA,
84
94
  template_id: TEMPLATE_ID,
85
95
  parent_path: z
86
96
  .string()
87
97
  .default('')
88
- .describe('JSON-Pointer of the parent node ("" for template root, ' +
89
- '"/0/children/2" for nested). Use yootheme_builder_element_list to find.'),
98
+ .describe('JSON-Pointer of the parent node. Accepts EITHER "" for ' +
99
+ 'template root, a `rel_path` from `element_list` ' +
100
+ '(`/children/0`, `/children/0/children/2`) — the server ' +
101
+ 'resolves it within this template — OR a fully-qualified ' +
102
+ 'pointer (`/templates/<id>/layout/children/0/...`). The ' +
103
+ 'rel_path form is preferred (copy-paste straight from ' +
104
+ '`element_list`).'),
90
105
  element_type: z
91
106
  .string()
92
107
  .min(1)
@@ -100,14 +115,16 @@ export function buildElementsTools(client, deps) {
100
115
  etag: ETAG,
101
116
  },
102
117
  annotations: creating('Add Element'),
103
- handler: (input, extra) => handleElementAdd(handlerDeps, input, extra),
118
+ handler: async ({ site_id, ...rest }, extra) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementAdd(makeDeps(client), rest, extra), site)),
104
119
  }),
105
120
  defineTool({
106
121
  name: 'yootheme_builder_element_update_settings',
107
122
  description: 'Update `props` on an element. Default replaces all props; pass ' +
108
123
  '`merge:true` for server-side deep-merge (only request keys overwritten, ' +
109
- 'others survive — avoids read-modify-write races). Requires ETag.',
124
+ 'others survive — avoids read-modify-write races). Requires ETag. ' +
125
+ 'Operates on the default site unless site_id is provided.',
110
126
  inputSchema: {
127
+ site_id: SITE_ID_SCHEMA,
111
128
  template_id: TEMPLATE_ID,
112
129
  element_path: ELEMENT_PATH,
113
130
  props: PROPS,
@@ -119,13 +136,15 @@ export function buildElementsTools(client, deps) {
119
136
  etag: ETAG,
120
137
  },
121
138
  annotations: mutating('Update Element Settings'),
122
- handler: (input, extra) => handleElementUpdateSettings(handlerDeps, input, extra),
139
+ handler: async ({ site_id, ...rest }, extra) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementUpdateSettings(makeDeps(client), rest, extra), site)),
123
140
  }),
124
141
  defineTool({
125
142
  name: 'yootheme_builder_element_move',
126
143
  description: 'Move an element to a new parent + index in the tree. Useful for reordering or ' +
127
- 'reparenting (e.g. moving a card from one grid column to another). Requires ETag.',
144
+ 'reparenting (e.g. moving a card from one grid column to another). Requires ETag. ' +
145
+ 'Operates on the default site unless site_id is provided.',
128
146
  inputSchema: {
147
+ site_id: SITE_ID_SCHEMA,
129
148
  template_id: TEMPLATE_ID,
130
149
  element_path: ELEMENT_PATH,
131
150
  to_parent_path: z
@@ -139,26 +158,29 @@ export function buildElementsTools(client, deps) {
139
158
  etag: ETAG,
140
159
  },
141
160
  annotations: mutating('Move Element'),
142
- handler: (input, extra) => handleElementMove(handlerDeps, input, extra),
161
+ handler: async ({ site_id, ...rest }, extra) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementMove(makeDeps(client), rest, extra), site)),
143
162
  }),
144
163
  defineTool({
145
164
  name: 'yootheme_builder_element_clone',
146
165
  description: 'Clone an element as a sibling (same parent, immediately after the source). ' +
147
- 'Returns the new element\'s path. Requires ETag.',
166
+ 'Returns the new element\'s path. Requires ETag. ' +
167
+ 'Operates on the default site unless site_id is provided.',
148
168
  inputSchema: {
169
+ site_id: SITE_ID_SCHEMA,
149
170
  template_id: TEMPLATE_ID,
150
171
  element_path: ELEMENT_PATH,
151
172
  etag: ETAG,
152
173
  },
153
174
  annotations: creating('Clone Element'),
154
- handler: (input, extra) => handleElementClone(handlerDeps, input, extra),
175
+ handler: async ({ site_id, ...rest }, extra) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementClone(makeDeps(client), rest, extra), site)),
155
176
  }),
156
177
  defineTool({
157
178
  name: 'yootheme_builder_element_delete',
158
179
  description: 'PERMANENTLY delete an element and all its children. Cannot be undone. Always ' +
159
180
  'ask the user to confirm first, then call again with `confirm: true`. Requires ' +
160
- 'ETag.',
181
+ 'ETag. Operates on the default site unless site_id is provided.',
161
182
  inputSchema: {
183
+ site_id: SITE_ID_SCHEMA,
162
184
  template_id: TEMPLATE_ID,
163
185
  element_path: ELEMENT_PATH,
164
186
  etag: ETAG,
@@ -170,7 +192,7 @@ export function buildElementsTools(client, deps) {
170
192
  'preview and the agent must retry with `confirm: true`.'),
171
193
  },
172
194
  annotations: destructive('Delete Element'),
173
- handler: (input, extra) => handleElementDelete(handlerDeps, input, extra),
195
+ handler: async ({ site_id, ...rest }, extra) => withSiteRetry(pool, site_id, async (client, site) => withSiteMeta(await handleElementDelete(makeDeps(client), rest, extra), site)),
174
196
  }),
175
197
  ];
176
198
  }