@salesforce/afv-skills 1.14.0 → 1.16.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 (365) hide show
  1. package/package.json +1 -1
  2. package/skills/activating-datacloud/SKILL.md +0 -1
  3. package/skills/analyzing-omnistudio-dependencies/SKILL.md +0 -1
  4. package/skills/applying-slds/SKILL.md +322 -0
  5. package/skills/applying-slds/checklists.md +83 -0
  6. package/skills/applying-slds/examples.md +283 -0
  7. package/skills/applying-slds/guidance/README.md +83 -0
  8. package/skills/applying-slds/guidance/blueprints-index.md +213 -0
  9. package/skills/applying-slds/guidance/icons-guidance.md +186 -0
  10. package/skills/applying-slds/guidance/overviews/borders.md +236 -0
  11. package/skills/applying-slds/guidance/overviews/color.md +266 -0
  12. package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
  13. package/skills/applying-slds/guidance/overviews/icons.md +240 -0
  14. package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
  15. package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
  16. package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
  17. package/skills/applying-slds/guidance/overviews/typography.md +323 -0
  18. package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
  19. package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
  20. package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
  21. package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
  22. package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
  23. package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
  24. package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
  25. package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
  26. package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
  27. package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
  28. package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
  29. package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
  30. package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
  31. package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
  32. package/skills/applying-slds/guidance/utilities/borders.md +131 -0
  33. package/skills/applying-slds/guidance/utilities/box.md +125 -0
  34. package/skills/applying-slds/guidance/utilities/color.md +165 -0
  35. package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
  36. package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
  37. package/skills/applying-slds/guidance/utilities/floats.md +117 -0
  38. package/skills/applying-slds/guidance/utilities/grid.md +264 -0
  39. package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
  40. package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
  41. package/skills/applying-slds/guidance/utilities/index.md +205 -0
  42. package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
  43. package/skills/applying-slds/guidance/utilities/layout.md +109 -0
  44. package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
  45. package/skills/applying-slds/guidance/utilities/margin.md +155 -0
  46. package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
  47. package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
  48. package/skills/applying-slds/guidance/utilities/padding.md +155 -0
  49. package/skills/applying-slds/guidance/utilities/position.md +177 -0
  50. package/skills/applying-slds/guidance/utilities/print.md +114 -0
  51. package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
  52. package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
  53. package/skills/applying-slds/guidance/utilities/themes.md +121 -0
  54. package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
  55. package/skills/applying-slds/guidance/utilities/typography.md +166 -0
  56. package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
  57. package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
  58. package/skills/applying-slds/metadata/README.md +84 -0
  59. package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
  60. package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
  61. package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
  62. package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
  63. package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
  64. package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
  65. package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
  66. package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
  67. package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
  68. package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
  69. package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
  70. package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
  71. package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
  72. package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
  73. package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
  74. package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
  75. package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
  76. package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
  77. package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
  78. package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
  79. package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
  80. package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
  81. package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
  82. package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
  83. package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
  84. package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
  85. package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
  86. package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
  87. package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
  88. package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
  89. package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
  90. package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
  91. package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
  92. package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
  93. package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
  94. package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
  95. package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
  96. package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
  97. package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
  98. package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
  99. package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
  100. package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
  101. package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
  102. package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
  103. package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
  104. package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
  105. package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
  106. package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
  107. package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
  108. package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
  109. package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
  110. package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
  111. package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
  112. package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
  113. package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
  114. package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
  115. package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
  116. package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
  117. package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
  118. package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
  119. package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
  120. package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
  121. package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
  122. package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
  123. package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
  124. package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
  125. package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
  126. package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
  127. package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
  128. package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
  129. package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
  130. package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
  131. package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
  132. package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
  133. package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
  134. package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
  135. package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
  136. package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
  137. package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
  138. package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
  139. package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
  140. package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
  141. package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
  142. package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
  143. package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
  144. package/skills/applying-slds/metadata/hooks-index.json +6272 -0
  145. package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
  146. package/skills/applying-slds/metadata/utilities-index.json +21912 -0
  147. package/skills/applying-slds/references/component-selection.md +112 -0
  148. package/skills/applying-slds/references/icons-decision-guide.md +124 -0
  149. package/skills/applying-slds/references/styling-decision-guide.md +228 -0
  150. package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
  151. package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
  152. package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
  153. package/skills/applying-slds/scripts/search-icons.cjs +174 -0
  154. package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
  155. package/skills/building-mobile-apps/SKILL.md +0 -1
  156. package/skills/building-omnistudio-callable-apex/SKILL.md +0 -1
  157. package/skills/building-omnistudio-datamapper/SKILL.md +0 -1
  158. package/skills/building-omnistudio-flexcard/SKILL.md +0 -1
  159. package/skills/building-omnistudio-integration-procedure/SKILL.md +0 -1
  160. package/skills/building-omnistudio-omniscript/SKILL.md +0 -1
  161. package/skills/building-sf-integrations/SKILL.md +0 -1
  162. package/skills/configuring-connected-apps/SKILL.md +0 -1
  163. package/skills/connecting-datacloud/SKILL.md +0 -1
  164. package/skills/creating-b2b-commerce-store/SKILL.md +0 -1
  165. package/skills/debugging-apex-logs/SKILL.md +0 -1
  166. package/skills/deploying-metadata/SKILL.md +0 -1
  167. package/skills/deploying-omnistudio-datapacks/SKILL.md +0 -1
  168. package/skills/developing-agentforce/SKILL.md +0 -1
  169. package/skills/fetching-salesforce-docs/SKILL.md +0 -1
  170. package/skills/generating-custom-lightning-type/SKILL.md +17 -39
  171. package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
  172. package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
  173. package/skills/generating-lwc-components/SKILL.md +0 -1
  174. package/skills/generating-mermaid-diagrams/SKILL.md +0 -1
  175. package/skills/generating-visual-diagrams/SKILL.md +0 -1
  176. package/skills/handling-sf-data/SKILL.md +0 -1
  177. package/skills/harmonizing-datacloud/SKILL.md +0 -1
  178. package/skills/integrating-b2b-commerce-open-code-components/SKILL.md +0 -1
  179. package/skills/investigating-agentforce-architecture/README.md +156 -0
  180. package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
  181. package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
  182. package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
  183. package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
  184. package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
  185. package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
  186. package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
  187. package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
  188. package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
  189. package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
  190. package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
  191. package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
  192. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
  193. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
  194. package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
  195. package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
  196. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
  197. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
  198. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
  199. package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
  200. package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
  201. package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
  202. package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
  203. package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
  204. package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
  205. package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
  206. package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
  207. package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
  208. package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
  209. package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
  210. package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
  211. package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
  212. package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
  213. package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
  214. package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
  215. package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
  216. package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
  217. package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
  218. package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
  219. package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
  220. package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
  221. package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
  222. package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
  223. package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
  224. package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
  225. package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
  226. package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
  227. package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
  228. package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
  229. package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
  230. package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
  231. package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
  232. package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
  233. package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
  234. package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
  235. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
  236. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
  237. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
  238. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
  239. package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
  240. package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
  241. package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
  242. package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
  243. package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
  244. package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
  245. package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
  246. package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
  247. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
  248. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
  249. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
  250. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
  251. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
  252. package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
  253. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
  254. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
  255. package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
  256. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
  257. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
  258. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
  259. package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
  260. package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
  261. package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
  262. package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
  263. package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
  264. package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
  265. package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
  266. package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
  267. package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
  268. package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
  269. package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
  270. package/skills/investigating-agentforce-d360/README.md +123 -0
  271. package/skills/investigating-agentforce-d360/SKILL.md +163 -0
  272. package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
  273. package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
  274. package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
  275. package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
  276. package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
  277. package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
  278. package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
  279. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
  280. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
  281. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
  282. package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
  283. package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
  284. package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
  285. package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
  286. package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
  287. package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
  288. package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
  289. package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
  290. package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
  291. package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
  292. package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
  293. package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
  294. package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
  295. package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
  296. package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
  297. package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
  298. package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
  299. package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
  300. package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
  301. package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
  302. package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
  303. package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
  304. package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
  305. package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
  306. package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
  307. package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
  308. package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
  309. package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
  310. package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
  311. package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
  312. package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
  313. package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
  314. package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
  315. package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
  316. package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
  317. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
  318. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
  319. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
  320. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
  321. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
  322. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
  323. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
  324. package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
  325. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
  326. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
  327. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
  328. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
  329. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
  330. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
  331. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
  332. package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
  333. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
  334. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
  335. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
  336. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
  337. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
  338. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
  339. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
  340. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
  341. package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
  342. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
  343. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
  344. package/skills/managing-managed-event-subscription/SKILL.md +152 -0
  345. package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
  346. package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
  347. package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
  348. package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
  349. package/skills/modeling-omnistudio-epc-catalog/SKILL.md +0 -1
  350. package/skills/observing-agentforce/SKILL.md +0 -1
  351. package/skills/orchestrating-datacloud/SKILL.md +0 -1
  352. package/skills/preparing-datacloud/SKILL.md +0 -1
  353. package/skills/querying-soql/SKILL.md +0 -1
  354. package/skills/retrieving-datacloud/SKILL.md +0 -1
  355. package/skills/running-apex-tests/SKILL.md +0 -1
  356. package/skills/running-code-analyzer/SKILL.md +0 -1
  357. package/skills/segmenting-datacloud/SKILL.md +0 -1
  358. package/skills/testing-agentforce/SKILL.md +0 -1
  359. package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
  360. package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
  361. package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
  362. package/skills/validating-slds/SKILL.md +262 -0
  363. package/skills/validating-slds/references/quality-checks.md +308 -0
  364. package/skills/validating-slds/references/report-format.md +302 -0
  365. package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
@@ -0,0 +1,689 @@
1
+ """SOQL-based body fetchers for Wave A (GenAi normalized DAG) + Wave B
2
+ (Flow / Apex body bodies).
3
+
4
+ Phase 2 Batch 1: this module is the single surface `main.py`'s orchestrator
5
+ composes against. Every function in this module is a thin wrapper over
6
+ `soql_loader` + `rest_client.{tooling_query, data_query}`. Three invariants:
7
+
8
+ 1. Credentials always flow through a `creds_provider` closure
9
+ (`Callable[[], tuple[str, str]]`) so `retry_on_401`'s refresh path
10
+ can deliver fresh creds into the retry. See rest_client
11
+ 2. Empty list inputs short-circuit to `[]` WITHOUT firing a SOQL call.
12
+ `load_soql_in` refuses empty lists (SF syntax error), so callers
13
+ upstream shouldn't have to guard every batch site — guard once here.
14
+ 3. `api_version` (.4-R4, 2026-05-02) is REQUIRED on every fetcher.
15
+ The prior `rest_client.tooling_query` pinned `v60.0` and that
16
+ floor was the source of on orgs running v66 — which
17
+ genuinely expose fields v60 does not (`BotDefinition.Description`
18
+ is the observed case). Callers read the version once via
19
+ `main._derive_org_ids` (from `sf org display --json`) and thread
20
+ it through here. Same defensive pattern as for
21
+ `on_401_refresh`: no default, so a missed call-site is a
22
+ TypeError at call time, not a silent regression.
23
+
24
+ All failure paths use `rest_client.redact_error` implicitly: the helpers
25
+ raise `RestClientError` with pre-redacted messages. Callers that log should
26
+ call `redact_error(exc)` themselves rather than `str(exc)` on any wrapped
27
+ urllib/subprocess exception — redaction at the reporting site is
28
+ defence-in-depth.
29
+
30
+ `on_401_refresh` is a REQUIRED keyword-only arg
31
+ on every fetcher in this module. The previous default (`on_401_refresh
32
+ or creds_provider`) silently collapsed to "re-read the same stale token"
33
+ when a caller passed `None` — the retry would hit the identical stale
34
+ token on the second attempt and 401 again, bypassing entirely.
35
+ Making the parameter required surfaces that misuse as a TypeError at
36
+ import/call time instead of as a silent auth failure under load.
37
+ """
38
+ from __future__ import annotations
39
+
40
+ import logging
41
+ import urllib.error
42
+ from typing import Callable, Tuple
43
+
44
+ from rest_client import data_query, tooling_query
45
+ from soql_loader import load_soql, load_soql_in
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+
50
+ CredsProvider = Callable[[], Tuple[str, str]]
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Small record-extraction helper. SF REST query responses wrap the row list
55
+ # under `.records`; tooling + data surfaces agree on this shape. One helper
56
+ # keeps the Wave A/B fetchers trivial — they call `_records(tooling_query(...))`
57
+ # and return a list[dict].
58
+ # ---------------------------------------------------------------------------
59
+
60
+
61
+ def _records(response: dict) -> list[dict]:
62
+ """Extract records list from a SOQL query response.
63
+
64
+ SF REST returns `{"totalSize": N, "done": true, "records": [...]}` on
65
+ both Data and Tooling APIs. A missing `records` key (malformed response,
66
+ empty result) degrades to `[]` — callers that need a single record
67
+ slice the list themselves; callers that batch don't have to branch on
68
+ "records missing".
69
+ """
70
+ if not isinstance(response, dict):
71
+ return []
72
+ recs = response.get("records")
73
+ if not isinstance(recs, list):
74
+ return []
75
+ return recs
76
+
77
+
78
+ # ===========================================================================
79
+ # Wave A — GenAi normalized fetchers (Tooling API only)
80
+ # ===========================================================================
81
+ # DAG, per plan section B.5:
82
+ #
83
+ # A1 planner_definition_by_agent_chain scalar: AGENT_NAME [+ VERSION]
84
+ # A2 plugins_by_planner scalar: PLANNER_ID
85
+ # A3 planner_bundle_functions scalar: PLANNER_ID
86
+ # A4 functions_by_plugins list: PLUGIN_IDS
87
+ # A5 plugin_instructions_by_plugin_ids list: PLUGIN_IDS
88
+ # A6 plugin_functions_by_plugin_ids list: PLUGIN_IDS
89
+ # A7 planner_attrs_by_parent_ids list: PARENT_IDS
90
+ #
91
+ # Ordering: A1 first (provides planner_id). Then A2 + A3 can parallelize.
92
+ # Once A2 yields plugin_ids, A4 / A5 / A6 parallelize. A7 last once A4
93
+ # yields function_ids.
94
+ # ---------------------------------------------------------------------------
95
+
96
+
97
+ def fetch_planner_definition(
98
+ agent_api_name: str,
99
+ version: str | None,
100
+ creds_provider: CredsProvider,
101
+ *,
102
+ api_version: str,
103
+ on_401_refresh: Callable[[], Tuple[str, str]],
104
+ ) -> dict | None:
105
+ """Wave A1: resolve the live GenAiPlannerDefinition for (agent, version).
106
+
107
+ Agentforce generates an accretive chain of planner DeveloperNames as
108
+ agents version up — v1 = `<Agent>`, v2 = `<Agent>_v2`, v3 =
109
+ `<Agent>_v2_v3`, ... The chain shape is unpredictable from
110
+ (agent, version) alone, but an invariant holds: for vN the
111
+ DeveloperName always starts with `<agent_api_name>` and ends with
112
+ `_v<N>` for N>=2; for v1 it is exactly `<agent_api_name>`. A single
113
+ SOQL LIKE lookup pinned to that shape lands on the correct row
114
+ regardless of chain depth.
115
+
116
+ Branching:
117
+ * `version` is None / empty / "v1" → exact match. SOQL built
118
+ inline as `LIKE '<agent_api_name>'` (no wildcards — degenerate
119
+ LIKE is equivalent to `=`). The v1 branch bypasses the chain
120
+ template because the template's `%\\_{{VERSION}}` tail has no
121
+ sensible empty-version rendering.
122
+ * v2+ → LIKE `<agent_api_name>%\\_<version>`. The backslash escapes
123
+ the single-char wildcard `_` so `_v2` matches literally, not as
124
+ "any character then v2".
125
+
126
+ Escaping note (2026-05-05): the SOQL template on disk carries `\\_`
127
+ (one backslash, one underscore) because the REST Query endpoint
128
+ consumes the body verbatim — no shell, no extra quoting layer. If a
129
+ future caller ever shells this through `bash -c`, the backslash would
130
+ need doubling; we don't currently have that call path.
131
+
132
+ Disambiguation: if the LIKE returns multiple rows (e.g. a longer
133
+ chain name ALSO matches the pattern because it happens to end in
134
+ `_v2` too), pick the shortest DeveloperName — the canonical chain
135
+ ends at exactly `<agent_api_name>...<_v{version}>` with no suffix,
136
+ so shortest always wins.
137
+
138
+ Returns the planner dict or `None` if no row matches.
139
+
140
+ `load_soql` revalidates each substituted value against
141
+ `[A-Za-z0-9_]+` . `agent_api_name` and `version` satisfy that
142
+ regex; the `%\\_` literals live in the SOQL template, not in a
143
+ substituted variable, so they never traverse the validator.
144
+ """
145
+ v = (version or "").strip()
146
+ if v in ("", "v1"):
147
+ # v1 branch: DeveloperName is exactly `<agent_api_name>`. A LIKE
148
+ # with no wildcards is equivalent to `=`. We can't re-use the
149
+ # chain template with an empty VERSION (load_soql rejects empty
150
+ # strings AND the template's trailing `%\_{{VERSION}}` wouldn't
151
+ # collapse cleanly), so build the SOQL directly here. We still
152
+ # run the agent_api_name through the same validator load_soql
153
+ # uses, so the v1 path has no weaker injection surface than the
154
+ # v2+ path.
155
+ from config import fs_guard # re-exported from _shared/
156
+ from soql_loader import SoqlParamError as _SoqlParamError
157
+ try:
158
+ fs_guard.validate_api_name(agent_api_name, label="AGENT_NAME")
159
+ except fs_guard.ValidationError as e:
160
+ raise _SoqlParamError("AGENT_NAME", agent_api_name, e.reason) from None
161
+ soql = (
162
+ "SELECT Id, DeveloperName, MasterLabel, Description, "
163
+ "PlannerType, Capabilities, AgentGraph\n"
164
+ "FROM GenAiPlannerDefinition\n"
165
+ f"WHERE DeveloperName LIKE '{agent_api_name}'"
166
+ )
167
+ else:
168
+ soql = load_soql(
169
+ "planner_definition_by_agent_chain",
170
+ AGENT_NAME=agent_api_name,
171
+ VERSION=v,
172
+ )
173
+ resp = tooling_query(
174
+ creds_provider, soql,
175
+ api_version=api_version,
176
+ on_401_refresh=on_401_refresh,
177
+ )
178
+ recs = _records(resp)
179
+ if not recs:
180
+ return None
181
+ # Disambiguate on shortest DeveloperName — the canonical chain row
182
+ # has no suffix beyond `_v<N>`. A longer row means the LIKE also
183
+ # matched a deeper-chain planner that happens to share the suffix.
184
+ recs.sort(key=lambda r: len(r.get("DeveloperName") or ""))
185
+ return recs[0]
186
+
187
+
188
+ def fetch_plugins_by_planner(
189
+ planner_id: str,
190
+ creds_provider: CredsProvider,
191
+ *,
192
+ api_version: str,
193
+ on_401_refresh: Callable[[], Tuple[str, str]],
194
+ ) -> list[dict]:
195
+ """Wave A2: topic list for a planner."""
196
+ soql = load_soql("plugins_by_planner", PLANNER_ID=planner_id)
197
+ resp = tooling_query(
198
+ creds_provider, soql,
199
+ api_version=api_version,
200
+ on_401_refresh=on_401_refresh,
201
+ )
202
+ return _records(resp)
203
+
204
+
205
+ def fetch_planner_bundle_functions(
206
+ planner_id: str,
207
+ creds_provider: CredsProvider,
208
+ *,
209
+ api_version: str,
210
+ on_401_refresh: Callable[[], Tuple[str, str]],
211
+ ) -> list[dict]:
212
+ """Wave A3: planner-bundle-scope function join rows (classic).
213
+
214
+ NGA planners have no bundle-scope functions (PlannerId is null on
215
+ every row); this query returns [] on NGA orgs. Caller doesn't have
216
+ to branch.
217
+ """
218
+ soql = load_soql("planner_bundle_functions", PLANNER_ID=planner_id)
219
+ resp = tooling_query(
220
+ creds_provider, soql,
221
+ api_version=api_version,
222
+ on_401_refresh=on_401_refresh,
223
+ )
224
+ return _records(resp)
225
+
226
+
227
+ def fetch_functions_by_plugins(
228
+ plugin_ids: list[str],
229
+ creds_provider: CredsProvider,
230
+ *,
231
+ api_version: str,
232
+ on_401_refresh: Callable[[], Tuple[str, str]],
233
+ ) -> list[dict]:
234
+ """Wave A4: actions (GenAiFunctionDefinition) under a planner's plugins.
235
+
236
+ User invariant: a planner never has direct functions (PlannerId-only
237
+ rows with no PluginId are orphan data, not live actions). The prior
238
+ `PlannerId = '<id>' OR ...` leg dragged in those orphans and
239
+ surfaced them as stray root-level children. The query is now a
240
+ single IN-list over plugin_ids; the PlannerId + ParentId columns
241
+ stay in the SELECT for downstream consumers (parse_bundle, etc.)
242
+ that still read them.
243
+
244
+ Empty `plugin_ids` short-circuits — a SequentialPlannerIntent-
245
+ Classifier bot with zero plugins has no plugin-scope functions to
246
+ fetch. `load_soql_in` refuses empty lists; we guard here so callers
247
+ don't have to.
248
+ """
249
+ if not plugin_ids:
250
+ return []
251
+ soql = load_soql_in(
252
+ "functions_by_plugins",
253
+ list_params={"PLUGIN_IDS": plugin_ids},
254
+ )
255
+ resp = tooling_query(
256
+ creds_provider, soql,
257
+ api_version=api_version,
258
+ on_401_refresh=on_401_refresh,
259
+ )
260
+ return _records(resp)
261
+
262
+
263
+ def fetch_plugin_instructions(
264
+ plugin_ids: list[str],
265
+ creds_provider: CredsProvider,
266
+ *,
267
+ api_version: str,
268
+ on_401_refresh: Callable[[], Tuple[str, str]],
269
+ ) -> list[dict]:
270
+ """Wave A5: per-topic instruction rows.
271
+
272
+ Empty `plugin_ids` → []; no SOQL fired. SequentialPlannerIntent-
273
+ Classifier bots and NGA single-planner shapes hit this path.
274
+ """
275
+ if not plugin_ids:
276
+ return []
277
+ soql = load_soql_in(
278
+ "plugin_instructions_by_plugin_ids",
279
+ list_params={"PLUGIN_IDS": plugin_ids},
280
+ )
281
+ resp = tooling_query(
282
+ creds_provider, soql,
283
+ api_version=api_version,
284
+ on_401_refresh=on_401_refresh,
285
+ )
286
+ return _records(resp)
287
+
288
+
289
+ def fetch_plugin_functions(
290
+ plugin_ids: list[str],
291
+ creds_provider: CredsProvider,
292
+ *,
293
+ api_version: str,
294
+ on_401_refresh: Callable[[], Tuple[str, str]],
295
+ ) -> list[dict]:
296
+ """Wave A6: plugin → function join rows."""
297
+ if not plugin_ids:
298
+ return []
299
+ soql = load_soql_in(
300
+ "plugin_functions_by_plugin_ids",
301
+ list_params={"PLUGIN_IDS": plugin_ids},
302
+ )
303
+ resp = tooling_query(
304
+ creds_provider, soql,
305
+ api_version=api_version,
306
+ on_401_refresh=on_401_refresh,
307
+ )
308
+ return _records(resp)
309
+
310
+
311
+ def fetch_planner_attrs(
312
+ parent_ids: list[str],
313
+ creds_provider: CredsProvider,
314
+ *,
315
+ api_version: str,
316
+ on_401_refresh: Callable[[], Tuple[str, str]],
317
+ ) -> list[dict]:
318
+ """Wave A7: attribute mappings for a list of parent ids.
319
+
320
+ Polymorphic ParentId: pass the UNION of function_ids + planner_id.
321
+ Bot shape with zero functions (no actions registered) → []; no SOQL
322
+ fired. Caller must include the planner_id even when function_ids is
323
+ empty — this helper doesn't fabricate it.
324
+ """
325
+ if not parent_ids:
326
+ return []
327
+ soql = load_soql_in(
328
+ "planner_attrs_by_parent_ids",
329
+ list_params={"PARENT_IDS": parent_ids},
330
+ )
331
+ resp = tooling_query(
332
+ creds_provider, soql,
333
+ api_version=api_version,
334
+ on_401_refresh=on_401_refresh,
335
+ )
336
+ return _records(resp)
337
+
338
+
339
+ # ===========================================================================
340
+ # Wave B — body fetchers (Flow, Apex). Tooling API.
341
+ # ===========================================================================
342
+ # These are the leaves: once Wave A gives us the function rows, we resolve
343
+ # every InvocationTarget into one of flow / apex / prompt (prompt body
344
+ # lands via retrieve in Batch 2, not here).
345
+ #
346
+ # The single-row Flow.Metadata path is the big parallelism opportunity —
347
+ # `fetch_flow_metadata` is called N times (one per version id) and
348
+ # dispatched through `parallel_retrieve.fetch_bodies_parallel`.
349
+ # ---------------------------------------------------------------------------
350
+
351
+
352
+ def fetch_apex_bodies_by_names(
353
+ names: list[str],
354
+ creds_provider: CredsProvider,
355
+ *,
356
+ api_version: str,
357
+ on_401_refresh: Callable[[], Tuple[str, str]],
358
+ ) -> list[dict]:
359
+ """Wave B3 classic: Apex bodies keyed by DeveloperName.
360
+
361
+ Returns `[{Id, Name, Body, SymbolTable, ApiVersion, IsValid}, ...]`.
362
+ Batch-safe on `Name IN (...)` even though SymbolTable is
363
+ complexvalue (confirmed live — see references/soql_fields.md).
364
+ """
365
+ if not names:
366
+ return []
367
+ soql = load_soql_in(
368
+ "apex_class_bodies_by_names",
369
+ list_params={"NAMES_LIST": names},
370
+ )
371
+ resp = tooling_query(
372
+ creds_provider, soql,
373
+ api_version=api_version,
374
+ on_401_refresh=on_401_refresh,
375
+ )
376
+ return _records(resp)
377
+
378
+
379
+ def fetch_apex_bodies_by_ids(
380
+ ids: list[str],
381
+ creds_provider: CredsProvider,
382
+ *,
383
+ api_version: str,
384
+ on_401_refresh: Callable[[], Tuple[str, str]],
385
+ ) -> list[dict]:
386
+ """Wave B3 NGA: Apex bodies keyed by Id.
387
+
388
+ NGA functions store InvocationTarget as Salesforce Ids (e.g. `01p...`);
389
+ this is the reverse-lookup path that translates back to Name + Body.
390
+ """
391
+ if not ids:
392
+ return []
393
+ soql = load_soql_in(
394
+ "apex_class_bodies_by_ids",
395
+ list_params={"APEX_IDS_LIST": ids},
396
+ )
397
+ resp = tooling_query(
398
+ creds_provider, soql,
399
+ api_version=api_version,
400
+ on_401_refresh=on_401_refresh,
401
+ )
402
+ return _records(resp)
403
+
404
+
405
+ def fetch_flow_definition_view_by_durable_ids(
406
+ durable_ids: list[str],
407
+ creds_provider: CredsProvider,
408
+ *,
409
+ api_version: str,
410
+ on_401_refresh: Callable[[], Tuple[str, str]],
411
+ ) -> list[dict]:
412
+ """Data API fallback: resolve managed-installed flow names via
413
+ `FlowDefinitionView`.
414
+
415
+ `FlowDefinition` (Tooling) does not index managed-installed flows for
416
+ subscriber orgs — the Tooling query for a `ns__BareName` returns zero
417
+ rows even when the flow genuinely exists. `FlowDefinitionView` (Data
418
+ API only, NOT Tooling) does expose those rows via its `DurableId`
419
+ column, which for managed-installed flows IS the qualified
420
+ `ns__BareName` string.
421
+
422
+ Caveats baked into the consumer contract (see
423
+ `fetch_flow_definition_ids_by_names` downstream projection):
424
+ * `FlowDefinitionView.ActiveVersionId` is a composite display
425
+ string (e.g. `SvcCopilotTmpl__VerifyCode-1`), not a real
426
+ `Flow.Id`. It cannot be used to fetch the flow body XML —
427
+ managed flow bodies are IP-protected and not retrievable.
428
+ * Callers must project these rows with `ActiveVersionId=None` and
429
+ `_body_available=False` so the Wave B metadata fetcher skips
430
+ body retrieval for them.
431
+
432
+ Empty input short-circuits to `[]` without firing a SOQL call —
433
+ matches the contract on every other list-shaped fetcher in this
434
+ module.
435
+ """
436
+ if not durable_ids:
437
+ return []
438
+ soql = load_soql_in(
439
+ "flow_definition_view_by_durable_ids",
440
+ list_params={"DURABLE_IDS_LIST": durable_ids},
441
+ )
442
+ resp = data_query(
443
+ creds_provider, soql,
444
+ api_version=api_version,
445
+ on_401_refresh=on_401_refresh,
446
+ )
447
+ return _records(resp)
448
+
449
+
450
+ def fetch_flow_definition_ids_by_names(
451
+ names: list[str],
452
+ creds_provider: CredsProvider,
453
+ *,
454
+ api_version: str,
455
+ on_401_refresh: Callable[[], Tuple[str, str]],
456
+ ) -> list[dict]:
457
+ """Wave B1 classic: resolve Flow DeveloperName list → FlowDefinition rows.
458
+
459
+ Returns `[{Id, DeveloperName, NamespacePrefix, ActiveVersionId,
460
+ _bare_developer_name, _source, _body_available, ...}, ...]`.
461
+ Two-hop to `Flow` via `ActiveVersionId`; this is the first hop.
462
+
463
+ Resolution path (2026-05-05, post-retirement of the managed-ns
464
+ Tooling bucket): fire ONE Tooling `FlowDefinition` query for every
465
+ input name verbatim — the template filters `NamespacePrefix IS NULL`
466
+ so only unmanaged rows come back. Managed names like
467
+ `ns__BareName` return zero rows from Tooling on subscriber orgs
468
+ regardless of how we bucket them (live scouting confirmed Tooling
469
+ FlowDefinition simply does not index managed-installed flows for
470
+ subscribers), so attempting per-namespace Tooling queries adds cost
471
+ and returns nothing useful. Anything the unmanaged query doesn't
472
+ resolve falls through to `FlowDefinitionView` (Data API), which DOES
473
+ expose managed-installed flows via `DurableId = ns__BareName`.
474
+
475
+ FlowDefinitionView rows carry `Id=None`, `ActiveVersionId=None`,
476
+ `_body_available=False`, and `_source="FlowDefinitionView"` so
477
+ downstream flow metadata retrieval short-circuits (there's no real
478
+ version Id to fetch a body with, and managed flow bodies are
479
+ IP-protected regardless).
480
+
481
+ Real Tooling rows carry `_source="FlowDefinition"` and
482
+ `_body_available=True` set explicitly — consumers can dispatch on
483
+ source rather than inferring from absence.
484
+ """
485
+ if not names:
486
+ return []
487
+
488
+ rows: list[dict] = []
489
+ # Track every input name we successfully resolve via the Tooling
490
+ # FlowDefinition path. Anything left over goes through the
491
+ # FlowDefinitionView fallback.
492
+ resolved_names: set[str] = set()
493
+
494
+ # Unmanaged Tooling query: template explicitly filters
495
+ # `NamespacePrefix = NULL`. Managed-qualified names (`ns__BareName`)
496
+ # passed through here will simply return zero rows — which is fine,
497
+ # the view fallback below catches them. The null-ns filter is
498
+ # load-bearing: dropping it would widen to unrelated managed rows
499
+ # that happen to collide on a bare DeveloperName.
500
+ #
501
+ # Bug G fix: the SOQL template uses `= NULL`, NOT `IS NULL`. Tooling
502
+ # Query API rejects `IS NULL` with `MALFORMED_QUERY: unexpected
503
+ # token: 'NamespacePrefix IS'`. Only the Data API parser accepts
504
+ # both forms. Commit aa01d52 mistakenly switched this template to
505
+ # `IS NULL` (to silence a Prizm scanner false-positive) on the
506
+ # premise that "both forms parse identically" — true for Data API,
507
+ # false for Tooling. That broke wave-B subflow resolution: every
508
+ # call here 400'd, the FDV fallback below also returned zero
509
+ # because it filters by Salesforce Id (300...), and BFS hit the
510
+ # iteration cap. Do NOT re-introduce `IS NULL` in this template.
511
+ soql = load_soql_in(
512
+ "flow_definition_ids_by_names",
513
+ list_params={"NAMES_LIST": list(names)},
514
+ )
515
+ # Bug D.2 fix: tolerate HTTPError on the Tooling call. A single name
516
+ # in `names` that violates Salesforce's DeveloperName limits (e.g.
517
+ # length >40 chars, or chars Salesforce treats as non-identifier
518
+ # despite passing fs_guard.validate_api_name) causes the WHOLE batch
519
+ # to 400. Without this `try`, the entire wave-B round failed and the
520
+ # FDV fallback below was never reached — managed names were never
521
+ # resolved, BFS hit the iteration cap, operator saw cryptic
522
+ # `wave-b-iteration-cap` entries instead of the actual root cause.
523
+ # On HTTPError, fall through with `resolved_names` empty so every
524
+ # input is re-tried via FDV; FDV uses Data API (different validation)
525
+ # and tends to accept names Tooling rejects.
526
+ try:
527
+ resp = tooling_query(
528
+ creds_provider, soql,
529
+ api_version=api_version,
530
+ on_401_refresh=on_401_refresh,
531
+ )
532
+ for r in _records(resp):
533
+ dev_name = r.get("DeveloperName")
534
+ if dev_name:
535
+ r["_bare_developer_name"] = dev_name
536
+ r["_source"] = "FlowDefinition"
537
+ r["_body_available"] = True
538
+ rows.append(r)
539
+ resolved_names.add(dev_name)
540
+ except urllib.error.HTTPError as exc:
541
+ # Don't propagate — the FDV fallback below handles every
542
+ # unresolved name. Log enough for triage; rest_client already
543
+ # attached `_response_body_preview` (Bug D.1) so the body is
544
+ # available downstream if a caller wants to inspect.
545
+ logger.debug(
546
+ "fetch_flow_definition_ids_by_names: Tooling batch failed "
547
+ "(HTTP %d); falling through to FlowDefinitionView for all %d names",
548
+ getattr(exc, "code", 0), len(names),
549
+ )
550
+
551
+ # FlowDefinitionView fallback — Data API. Any input name Tooling
552
+ # didn't resolve is re-queried as a DurableId. Managed-installed
553
+ # flows are the motivating case; the view also covers unmanaged
554
+ # rows the Tooling surface misses for any other reason.
555
+ unresolved_names = [n for n in names if n not in resolved_names]
556
+ if unresolved_names:
557
+ view_rows = fetch_flow_definition_view_by_durable_ids(
558
+ sorted(set(unresolved_names)),
559
+ creds_provider,
560
+ api_version=api_version,
561
+ on_401_refresh=on_401_refresh,
562
+ )
563
+ for view_row in view_rows:
564
+ durable_id = view_row.get("DurableId")
565
+ if not durable_id:
566
+ continue
567
+ rows.append({
568
+ "Id": None,
569
+ # Qualified ns__bare (matches bundle invocationTarget +
570
+ # parse_wave visited-set dedupe key).
571
+ "DeveloperName": durable_id,
572
+ "NamespacePrefix": view_row.get("NamespacePrefix"),
573
+ # ActiveVersionId on FlowDefinitionView is a composite
574
+ # display string (`ns__Name-<n>`), NOT a real Flow.Id.
575
+ # Null it so downstream `fetch_flow_metadata` dispatch
576
+ # skips body retrieval for these rows.
577
+ "ActiveVersionId": None,
578
+ "_bare_developer_name": view_row.get("ApiName"),
579
+ "_body_available": False,
580
+ "_source": "FlowDefinitionView",
581
+ "_flow_view_label": view_row.get("Label"),
582
+ "_flow_view_manageable_state": view_row.get("ManageableState"),
583
+ })
584
+
585
+ return rows
586
+
587
+
588
+ def fetch_flow_definition_by_ids(
589
+ ids: list[str],
590
+ creds_provider: CredsProvider,
591
+ *,
592
+ api_version: str,
593
+ on_401_refresh: Callable[[], Tuple[str, str]],
594
+ ) -> list[dict]:
595
+ """Wave B1 NGA: reverse-lookup FlowDefinition Id → DeveloperName.
596
+
597
+ NGA functions store Ids (`300...`). This resolves them back to names
598
+ so the tree's leaf nodes can carry the human-readable DeveloperName
599
+ and the active version id for Wave B2.
600
+ """
601
+ if not ids:
602
+ return []
603
+ soql = load_soql_in(
604
+ "flow_definition_by_ids",
605
+ list_params={"FLOW_DEF_IDS_LIST": ids},
606
+ )
607
+ resp = tooling_query(
608
+ creds_provider, soql,
609
+ api_version=api_version,
610
+ on_401_refresh=on_401_refresh,
611
+ )
612
+ return _records(resp)
613
+
614
+
615
+ def fetch_flow_metadata(
616
+ flow_version_id: str,
617
+ creds_provider: CredsProvider,
618
+ *,
619
+ api_version: str,
620
+ on_401_refresh: Callable[[], Tuple[str, str]],
621
+ ) -> dict | None:
622
+ """Wave B2: single-row Flow.Metadata fetch.
623
+
624
+ `complexvalue` fields (Metadata + FullName) force a single-row
625
+ retrieval (`WHERE Id = '<id>'`). Returns the row dict or `None` on
626
+ miss. Called once per version id; parallelism happens in `main.py`
627
+ via `parallel_retrieve.fetch_bodies_parallel`.
628
+ """
629
+ soql = load_soql("flow_metadata_by_id", FLOW_VERSION_ID=flow_version_id)
630
+ resp = tooling_query(
631
+ creds_provider, soql,
632
+ api_version=api_version,
633
+ on_401_refresh=on_401_refresh,
634
+ )
635
+ recs = _records(resp)
636
+ return recs[0] if recs else None
637
+
638
+
639
+ # ===========================================================================
640
+ # Bot resolution (Data API) — Phase 4 of main.py. Separate from Wave A/B
641
+ # because the routing is DATA_QUERY not tooling, and the shape is simpler.
642
+ # ===========================================================================
643
+
644
+
645
+ def fetch_bot_versions(
646
+ agent_api_name: str,
647
+ creds_provider: CredsProvider,
648
+ *,
649
+ api_version: str,
650
+ on_401_refresh: Callable[[], Tuple[str, str]],
651
+ ) -> list[dict]:
652
+ """Data API: resolve bot versions for a given bot DeveloperName.
653
+
654
+ Mirrors `resolve_bot.py` step 1 but routed through `data_query` so
655
+ the 401-refresh path is active. `resolve_bot.py` itself shells out
656
+ to `sf data query` and is retained as the env-var-driven entry-point
657
+ for Bash harness callers; `main.py` uses this in-process variant.
658
+ """
659
+ soql = load_soql("bot_version_lookup", AGENT_API_NAME=agent_api_name)
660
+ resp = data_query(
661
+ creds_provider, soql,
662
+ api_version=api_version,
663
+ on_401_refresh=on_401_refresh,
664
+ )
665
+ return _records(resp)
666
+
667
+
668
+ def fetch_bot_definition_details(
669
+ agent_api_name: str,
670
+ creds_provider: CredsProvider,
671
+ *,
672
+ api_version: str,
673
+ on_401_refresh: Callable[[], Tuple[str, str]],
674
+ ) -> dict | None:
675
+ """Data API: BotDefinition metadata (MasterLabel, AgentTemplate, ...).
676
+
677
+ Returns the single matching BotDefinition row or None. Feeds the
678
+ `tree["agent"]` fields in parse_wave's init_tree.
679
+ """
680
+ soql = load_soql("bot_definition_details", AGENT_API_NAME=agent_api_name)
681
+ resp = data_query(
682
+ creds_provider, soql,
683
+ api_version=api_version,
684
+ on_401_refresh=on_401_refresh,
685
+ )
686
+ recs = _records(resp)
687
+ return recs[0] if recs else None
688
+
689
+