@salesforce/afv-skills 1.13.0 → 1.15.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 (359) hide show
  1. package/package.json +3 -3
  2. package/skills/applying-slds/SKILL.md +322 -0
  3. package/skills/applying-slds/checklists.md +83 -0
  4. package/skills/applying-slds/examples.md +283 -0
  5. package/skills/applying-slds/guidance/README.md +83 -0
  6. package/skills/applying-slds/guidance/blueprints-index.md +213 -0
  7. package/skills/applying-slds/guidance/icons-guidance.md +186 -0
  8. package/skills/applying-slds/guidance/overviews/borders.md +236 -0
  9. package/skills/applying-slds/guidance/overviews/color.md +266 -0
  10. package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
  11. package/skills/applying-slds/guidance/overviews/icons.md +240 -0
  12. package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
  13. package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
  14. package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
  15. package/skills/applying-slds/guidance/overviews/typography.md +323 -0
  16. package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
  17. package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
  18. package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
  19. package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
  20. package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
  21. package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
  22. package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
  23. package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
  24. package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
  25. package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
  26. package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
  27. package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
  28. package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
  29. package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
  30. package/skills/applying-slds/guidance/utilities/borders.md +131 -0
  31. package/skills/applying-slds/guidance/utilities/box.md +125 -0
  32. package/skills/applying-slds/guidance/utilities/color.md +165 -0
  33. package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
  34. package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
  35. package/skills/applying-slds/guidance/utilities/floats.md +117 -0
  36. package/skills/applying-slds/guidance/utilities/grid.md +264 -0
  37. package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
  38. package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
  39. package/skills/applying-slds/guidance/utilities/index.md +205 -0
  40. package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
  41. package/skills/applying-slds/guidance/utilities/layout.md +109 -0
  42. package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
  43. package/skills/applying-slds/guidance/utilities/margin.md +155 -0
  44. package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
  45. package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
  46. package/skills/applying-slds/guidance/utilities/padding.md +155 -0
  47. package/skills/applying-slds/guidance/utilities/position.md +177 -0
  48. package/skills/applying-slds/guidance/utilities/print.md +114 -0
  49. package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
  50. package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
  51. package/skills/applying-slds/guidance/utilities/themes.md +121 -0
  52. package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
  53. package/skills/applying-slds/guidance/utilities/typography.md +166 -0
  54. package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
  55. package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
  56. package/skills/applying-slds/metadata/README.md +84 -0
  57. package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
  58. package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
  59. package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
  60. package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
  61. package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
  62. package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
  63. package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
  64. package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
  65. package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
  66. package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
  67. package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
  68. package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
  69. package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
  70. package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
  71. package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
  72. package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
  73. package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
  74. package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
  75. package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
  76. package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
  77. package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
  78. package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
  79. package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
  80. package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
  81. package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
  82. package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
  83. package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
  84. package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
  85. package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
  86. package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
  87. package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
  88. package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
  89. package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
  90. package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
  91. package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
  92. package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
  93. package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
  94. package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
  95. package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
  96. package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
  97. package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
  98. package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
  99. package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
  100. package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
  101. package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
  102. package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
  103. package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
  104. package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
  105. package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
  106. package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
  107. package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
  108. package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
  109. package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
  110. package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
  111. package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
  112. package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
  113. package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
  114. package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
  115. package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
  116. package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
  117. package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
  118. package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
  119. package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
  120. package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
  121. package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
  122. package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
  123. package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
  124. package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
  125. package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
  126. package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
  127. package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
  128. package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
  129. package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
  130. package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
  131. package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
  132. package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
  133. package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
  134. package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
  135. package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
  136. package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
  137. package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
  138. package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
  139. package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
  140. package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
  141. package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
  142. package/skills/applying-slds/metadata/hooks-index.json +6272 -0
  143. package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
  144. package/skills/applying-slds/metadata/utilities-index.json +21912 -0
  145. package/skills/applying-slds/references/component-selection.md +112 -0
  146. package/skills/applying-slds/references/icons-decision-guide.md +124 -0
  147. package/skills/applying-slds/references/styling-decision-guide.md +228 -0
  148. package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
  149. package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
  150. package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
  151. package/skills/applying-slds/scripts/search-icons.cjs +174 -0
  152. package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
  153. package/skills/building-ui-bundle-app/SKILL.md +33 -8
  154. package/skills/generating-custom-application/SKILL.md +1 -1
  155. package/skills/generating-custom-lightning-type/SKILL.md +17 -39
  156. package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
  157. package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
  158. package/skills/generating-ui-bundle-custom-app/SKILL.md +93 -0
  159. package/skills/generating-ui-bundle-custom-app/docs/configure-metadata-custom-application.md +70 -0
  160. package/skills/generating-ui-bundle-metadata/SKILL.md +39 -1
  161. package/skills/investigating-agentforce-architecture/README.md +156 -0
  162. package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
  163. package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
  164. package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
  165. package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
  166. package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
  167. package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
  168. package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
  169. package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
  170. package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
  171. package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
  172. package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
  173. package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
  174. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
  175. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
  176. package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
  177. package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
  178. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
  179. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
  180. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
  181. package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
  182. package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
  183. package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
  184. package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
  185. package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
  186. package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
  187. package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
  188. package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
  189. package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
  190. package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
  191. package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
  192. package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
  193. package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
  194. package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
  195. package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
  196. package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
  197. package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
  198. package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
  199. package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
  200. package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
  201. package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
  202. package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
  203. package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
  204. package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
  205. package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
  206. package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
  207. package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
  208. package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
  209. package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
  210. package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
  211. package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
  212. package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
  213. package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
  214. package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
  215. package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
  216. package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
  217. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
  218. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
  219. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
  220. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
  221. package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
  222. package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
  223. package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
  224. package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
  225. package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
  226. package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
  227. package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
  228. package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
  229. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
  230. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
  231. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
  232. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
  233. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
  234. package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
  235. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
  236. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
  237. package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
  238. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
  239. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
  240. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
  241. package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
  242. package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
  243. package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
  244. package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
  245. package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
  246. package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
  247. package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
  248. package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
  249. package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
  250. package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
  251. package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
  252. package/skills/investigating-agentforce-d360/README.md +123 -0
  253. package/skills/investigating-agentforce-d360/SKILL.md +163 -0
  254. package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
  255. package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
  256. package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
  257. package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
  258. package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
  259. package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
  260. package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
  261. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
  262. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
  263. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
  264. package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
  265. package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
  266. package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
  267. package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
  268. package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
  269. package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
  270. package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
  271. package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
  272. package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
  273. package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
  274. package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
  275. package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
  276. package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
  277. package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
  278. package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
  279. package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
  280. package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
  281. package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
  282. package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
  283. package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
  284. package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
  285. package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
  286. package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
  287. package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
  288. package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
  289. package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
  290. package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
  291. package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
  292. package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
  293. package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
  294. package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
  295. package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
  296. package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
  297. package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
  298. package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
  299. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
  300. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
  301. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
  302. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
  303. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
  304. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
  305. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
  306. package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
  307. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
  308. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
  309. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
  310. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
  311. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
  312. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
  313. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
  314. package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
  315. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
  316. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
  317. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
  318. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
  319. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
  320. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
  321. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
  322. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
  323. package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
  324. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
  325. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
  326. package/skills/managing-managed-event-subscription/SKILL.md +152 -0
  327. package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
  328. package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
  329. package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
  330. package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
  331. package/skills/reviewing-lwc-mobile-offline/SKILL.md +168 -0
  332. package/skills/reviewing-lwc-mobile-offline/references/grounding.md +7 -0
  333. package/skills/reviewing-lwc-mobile-offline/references/inline-graphql.md +43 -0
  334. package/skills/reviewing-lwc-mobile-offline/references/komaci-eslint.md +125 -0
  335. package/skills/reviewing-lwc-mobile-offline/references/lwc-if.md +78 -0
  336. package/skills/reviewing-lwc-mobile-offline/scripts/komaci.config.mjs +18 -0
  337. package/skills/reviewing-lwc-mobile-offline/scripts/package.json +10 -0
  338. package/skills/reviewing-lwc-mobile-offline/scripts/run-komaci.sh +69 -0
  339. package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
  340. package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
  341. package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
  342. package/skills/using-mobile-native-capabilities/SKILL.md +182 -0
  343. package/skills/using-mobile-native-capabilities/references/app-review.md +68 -0
  344. package/skills/using-mobile-native-capabilities/references/ar-space-capture.md +125 -0
  345. package/skills/using-mobile-native-capabilities/references/barcode-scanner.md +219 -0
  346. package/skills/using-mobile-native-capabilities/references/base-capability.md +22 -0
  347. package/skills/using-mobile-native-capabilities/references/biometrics.md +90 -0
  348. package/skills/using-mobile-native-capabilities/references/calendar.md +213 -0
  349. package/skills/using-mobile-native-capabilities/references/contacts.md +232 -0
  350. package/skills/using-mobile-native-capabilities/references/document-scanner.md +342 -0
  351. package/skills/using-mobile-native-capabilities/references/geofencing.md +123 -0
  352. package/skills/using-mobile-native-capabilities/references/location.md +158 -0
  353. package/skills/using-mobile-native-capabilities/references/mobile-capabilities.md +30 -0
  354. package/skills/using-mobile-native-capabilities/references/nfc.md +181 -0
  355. package/skills/using-mobile-native-capabilities/references/payments.md +95 -0
  356. package/skills/validating-slds/SKILL.md +262 -0
  357. package/skills/validating-slds/references/quality-checks.md +308 -0
  358. package/skills/validating-slds/references/report-format.md +302 -0
  359. package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
@@ -0,0 +1,203 @@
1
+ """Tests for ``resolve_bot`` — Bot + version resolution helpers + main flow.
2
+
3
+ Covers the small pure helpers (``scrub``, ``natural_key``,
4
+ ``emit_error_block``) plus a happy-path ``main`` end-to-end with
5
+ ``subprocess.run`` mocked.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ import unittest
12
+ from pathlib import Path
13
+ from tempfile import TemporaryDirectory
14
+ from types import SimpleNamespace
15
+ from unittest import mock
16
+
17
+ from . import _bootstrap # noqa: F401 — sys.path setup
18
+
19
+ import resolve_bot # type: ignore
20
+
21
+
22
+ # -----------------------------------------------------------------------------
23
+ # scrub
24
+ # -----------------------------------------------------------------------------
25
+
26
+
27
+ class ScrubTests(unittest.TestCase):
28
+
29
+ def test_strips_dangerous_shell_chars(self):
30
+ # ` $ " \\ \r \t \0 \n all stripped; safe chars kept verbatim.
31
+ self.assertEqual(
32
+ resolve_bot.scrub("hello`bad$\"" + "\n" + "world"),
33
+ "hellobadworld",
34
+ )
35
+
36
+ def test_strips_carriage_return_and_tab(self):
37
+ self.assertEqual(resolve_bot.scrub("a\tb\rc"), "abc")
38
+
39
+ def test_returns_empty_string_for_none(self):
40
+ self.assertEqual(resolve_bot.scrub(None), "")
41
+
42
+ def test_coerces_non_strings(self):
43
+ self.assertEqual(resolve_bot.scrub(42), "42")
44
+
45
+ def test_passes_safe_chars_through(self):
46
+ self.assertEqual(resolve_bot.scrub("Customer_Support_Agent"),
47
+ "Customer_Support_Agent")
48
+
49
+
50
+ # -----------------------------------------------------------------------------
51
+ # natural_key — version sorting
52
+ # -----------------------------------------------------------------------------
53
+
54
+
55
+ class NaturalKeyTests(unittest.TestCase):
56
+
57
+ def test_sorts_v10_after_v9(self):
58
+ keys = ["v9", "v10", "v2", "v1"]
59
+ keys.sort(key=resolve_bot.natural_key, reverse=True)
60
+ self.assertEqual(keys, ["v10", "v9", "v2", "v1"])
61
+
62
+ def test_handles_none_and_empty_string(self):
63
+ # Both should be safe (empty list)
64
+ self.assertEqual(resolve_bot.natural_key(""), [""])
65
+ self.assertEqual(resolve_bot.natural_key(None), [""])
66
+
67
+
68
+ # -----------------------------------------------------------------------------
69
+ # emit_error_block — terminal RESULT block + sys.exit
70
+ # -----------------------------------------------------------------------------
71
+
72
+
73
+ class EmitErrorBlockTests(unittest.TestCase):
74
+
75
+ def test_emits_result_block_and_exits_one(self):
76
+ old_env = dict(os.environ)
77
+ os.environ["AGENT_API_NAME"] = "MyAgent"
78
+ os.environ["ORG_ID_15"] = "00D000000000000"
79
+ os.environ["ORG_ID_18"] = "00D000000000000EAA"
80
+ os.environ.pop("ERROR_TEE", None)
81
+ try:
82
+ with mock.patch.object(resolve_bot.sys, "stdout") as out:
83
+ with self.assertRaises(SystemExit) as ctx:
84
+ resolve_bot.emit_error_block(
85
+ "AGENT_NOT_FOUND", "details here", {"AVAILABLE_BOTS": "A,B"},
86
+ )
87
+ self.assertEqual(ctx.exception.code, 1)
88
+ written = "".join(c.args[0] for c in out.write.call_args_list)
89
+ self.assertIn("STATUS=AGENT_NOT_FOUND", written)
90
+ self.assertIn("ERROR_DETAIL=details here", written)
91
+ self.assertIn("AGENT_API_NAME=MyAgent", written)
92
+ self.assertIn("AVAILABLE_BOTS=A,B", written)
93
+ finally:
94
+ os.environ.clear()
95
+ os.environ.update(old_env)
96
+
97
+ def test_writes_error_tee_when_env_set(self):
98
+ with TemporaryDirectory() as t:
99
+ tee_path = Path(t) / "subdir" / "tee.txt"
100
+ old_env = dict(os.environ)
101
+ os.environ["ERROR_TEE"] = str(tee_path)
102
+ os.environ["AGENT_API_NAME"] = "MyAgent"
103
+ os.environ["ORG_ID_15"] = "x"
104
+ os.environ["ORG_ID_18"] = "y"
105
+ try:
106
+ with mock.patch.object(resolve_bot.sys, "stdout"):
107
+ with self.assertRaises(SystemExit):
108
+ resolve_bot.emit_error_block("X", "y", {})
109
+ # tee_path got the same content
110
+ self.assertTrue(tee_path.is_file())
111
+ self.assertIn("STATUS=X", tee_path.read_text())
112
+ finally:
113
+ os.environ.clear()
114
+ os.environ.update(old_env)
115
+
116
+
117
+ # -----------------------------------------------------------------------------
118
+ # main — happy path with mocked sf data query
119
+ # -----------------------------------------------------------------------------
120
+
121
+
122
+ def _versions_payload() -> str:
123
+ return json.dumps({
124
+ "result": {
125
+ "records": [
126
+ {"DeveloperName": "v3", "Status": "Active",
127
+ "BotDefinitionId": "0Xx000000000ABC",
128
+ "BotDefinition": {"DeveloperName": "MyAgent",
129
+ "MasterLabel": "My Agent"}},
130
+ {"DeveloperName": "v2", "Status": "Inactive",
131
+ "BotDefinitionId": "0Xx000000000ABC",
132
+ "BotDefinition": {"DeveloperName": "MyAgent",
133
+ "MasterLabel": "My Agent"}},
134
+ ],
135
+ },
136
+ })
137
+
138
+
139
+ def _bot_def_payload() -> str:
140
+ return json.dumps({
141
+ "result": {
142
+ "records": [
143
+ {"DeveloperName": "MyAgent", "MasterLabel": "My Agent",
144
+ "Description": "demo", "AgentType": "Internal",
145
+ "Type": "AiCopilot", "AgentTemplate": "T",
146
+ "BotSource": "AgentforceAgentCopilot"},
147
+ ],
148
+ },
149
+ })
150
+
151
+
152
+ class MainTests(unittest.TestCase):
153
+
154
+ def _run_main(self, *, agent_version: str = "") -> tuple[int, str]:
155
+ old_env = dict(os.environ)
156
+ with TemporaryDirectory() as t:
157
+ tmp = Path(t)
158
+ os.environ["ORG_ALIAS"] = "my-org"
159
+ os.environ["AGENT_API_NAME"] = "MyAgent"
160
+ os.environ["WORK_DIR"] = str(tmp)
161
+ os.environ["AGENT_VERSION"] = agent_version
162
+
163
+ calls: list = []
164
+
165
+ def fake_run(argv, **kw):
166
+ # Two distinct sf data queries: BotVersion then BotDefinition
167
+ calls.append(argv)
168
+ if "BotVersion" in argv[-1]:
169
+ return SimpleNamespace(returncode=0, stdout=_versions_payload(), stderr="")
170
+ if "BotDefinition" in argv[-1]:
171
+ return SimpleNamespace(returncode=0, stdout=_bot_def_payload(), stderr="")
172
+ return SimpleNamespace(returncode=0, stdout="{}", stderr="")
173
+
174
+ stdout_buf: list[str] = []
175
+
176
+ try:
177
+ with mock.patch.object(resolve_bot.subprocess, "run", side_effect=fake_run):
178
+ with mock.patch.object(resolve_bot.sys, "stdout") as out:
179
+ out.write = lambda s: stdout_buf.append(s)
180
+ rc = resolve_bot.main()
181
+ finally:
182
+ os.environ.clear()
183
+ os.environ.update(old_env)
184
+ return rc, "".join(stdout_buf)
185
+
186
+ def test_main_succeeds_with_auto_pick(self):
187
+ rc, written = self._run_main()
188
+ self.assertEqual(rc, 0)
189
+ # v3 is Active and lexically highest → auto-picked
190
+ self.assertIn("AGENT_VERSION=v3", written)
191
+ self.assertIn("VERSION_AUTO_PICKED=true", written)
192
+ self.assertIn("BOT_FOUND=true", written)
193
+ self.assertIn("BOT_ID=0Xx000000000ABC", written)
194
+
195
+ def test_main_succeeds_with_explicit_version_match(self):
196
+ rc, written = self._run_main(agent_version="v2")
197
+ self.assertEqual(rc, 0)
198
+ self.assertIn("AGENT_VERSION=v2", written)
199
+ self.assertIn("VERSION_AUTO_PICKED=false", written)
200
+
201
+
202
+ if __name__ == "__main__":
203
+ unittest.main()
@@ -0,0 +1,157 @@
1
+ """Tests for ``main._resolve_creds`` — the two-path access-token retrieval
2
+ introduced for forcedotcom/cli#3560 (sf CLI v2 redaction, effective
3
+ 2026-05-27).
4
+
5
+ Path 1 (primary): ``sf org auth show-access-token --json --no-prompt``
6
+ via the ``show_access_token`` recipe.
7
+ Path 2 (fallback): ``sf org display`` payload with
8
+ ``SF_TEMP_SHOW_SECRETS=true`` env var.
9
+
10
+ We mock ``run_sf`` (not subprocess) since these tests target the
11
+ orchestration logic in ``main.py``, not the recipe loader. The recipe
12
+ loader and subprocess env injection have their own coverage in
13
+ ``test_sf_cli.py``.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import unittest
18
+ from unittest import mock
19
+
20
+ from . import _bootstrap # noqa: F401 — sys.path setup
21
+
22
+ import main # type: ignore
23
+ from sf_cli import AuthRequired, SfCliError # type: ignore
24
+
25
+
26
+ REDACTED_TOKEN = "[REDACTED] Use 'sf org auth show-access-token' to view"
27
+
28
+
29
+ def _display_payload(*, instance_url="https://example.salesforce.com",
30
+ access_token="TOKEN_FROM_DISPLAY"):
31
+ return {"result": {
32
+ "instanceUrl": instance_url,
33
+ "accessToken": access_token,
34
+ }}
35
+
36
+
37
+ def _show_token_payload(*, access_token="TOKEN_FROM_SHOW"):
38
+ return {"result": {"accessToken": access_token}}
39
+
40
+
41
+ class ResolveCredsTests(unittest.TestCase):
42
+ """Cover every branch of the two-path retrieval."""
43
+
44
+ def _route(self, *, primary_payload=None, primary_exc=None,
45
+ display_payload=None):
46
+ """Build a ``run_sf`` side-effect that dispatches by recipe name."""
47
+ display = display_payload or _display_payload()
48
+ primary = primary_payload or _show_token_payload()
49
+
50
+ def fake_run_sf(name, **params):
51
+ if name == "org_display":
52
+ return display
53
+ if name == "show_access_token":
54
+ if primary_exc is not None:
55
+ raise primary_exc
56
+ return primary
57
+ raise AssertionError(f"unexpected recipe: {name}")
58
+
59
+ return fake_run_sf
60
+
61
+ def test_primary_path_returns_show_token(self):
62
+ """Happy path — dedicated command returns a clean token."""
63
+ with mock.patch.object(main, "run_sf", side_effect=self._route()):
64
+ url, token = main._resolve_creds("my-org")
65
+ self.assertEqual(url, "https://example.salesforce.com")
66
+ self.assertEqual(token, "TOKEN_FROM_SHOW")
67
+
68
+ def test_primary_unknown_falls_back_to_display(self):
69
+ """Older sf CLI without the dedicated command surfaces SfCliError;
70
+ we fall back to the display payload's accessToken."""
71
+ with mock.patch.object(
72
+ main, "run_sf",
73
+ side_effect=self._route(
74
+ primary_exc=SfCliError("sf CLI 'show_access_token' failed"),
75
+ ),
76
+ ):
77
+ url, token = main._resolve_creds("my-org")
78
+ self.assertEqual(url, "https://example.salesforce.com")
79
+ self.assertEqual(token, "TOKEN_FROM_DISPLAY")
80
+
81
+ def test_primary_returns_redacted_token_falls_back(self):
82
+ """Edge case: dedicated command runs cleanly but returns the
83
+ placeholder string. Treat as failure and use the display fallback."""
84
+ with mock.patch.object(
85
+ main, "run_sf",
86
+ side_effect=self._route(
87
+ primary_payload=_show_token_payload(access_token=REDACTED_TOKEN),
88
+ ),
89
+ ):
90
+ _, token = main._resolve_creds("my-org")
91
+ self.assertEqual(token, "TOKEN_FROM_DISPLAY")
92
+
93
+ def test_primary_returns_empty_token_falls_back(self):
94
+ """Empty string from the dedicated command also triggers fallback."""
95
+ with mock.patch.object(
96
+ main, "run_sf",
97
+ side_effect=self._route(
98
+ primary_payload=_show_token_payload(access_token=""),
99
+ ),
100
+ ):
101
+ _, token = main._resolve_creds("my-org")
102
+ self.assertEqual(token, "TOKEN_FROM_DISPLAY")
103
+
104
+ def test_both_paths_redacted_raises_authrequired(self):
105
+ """If both paths come back redacted/empty, surface AuthRequired
106
+ rather than handing the placeholder to downstream Tooling/REST
107
+ callers (which would 401 with INVALID_AUTH_HEADER)."""
108
+ with mock.patch.object(
109
+ main, "run_sf",
110
+ side_effect=self._route(
111
+ primary_payload=_show_token_payload(access_token=REDACTED_TOKEN),
112
+ display_payload=_display_payload(access_token=REDACTED_TOKEN),
113
+ ),
114
+ ):
115
+ with self.assertRaises(AuthRequired) as ctx:
116
+ main._resolve_creds("my-org")
117
+ self.assertIn("could not retrieve a usable access token", str(ctx.exception))
118
+
119
+ def test_missing_instance_url_raises_authrequired(self):
120
+ """display returning empty instanceUrl is a hard failure — no
121
+ amount of token-juggling helps if we can't talk to the org."""
122
+ with mock.patch.object(
123
+ main, "run_sf",
124
+ side_effect=self._route(
125
+ display_payload=_display_payload(instance_url=""),
126
+ ),
127
+ ):
128
+ with self.assertRaises(AuthRequired) as ctx:
129
+ main._resolve_creds("my-org")
130
+ self.assertIn("instanceUrl", str(ctx.exception))
131
+
132
+ def test_primary_path_recipe_name_is_show_access_token(self):
133
+ """Tripwire — the primary call MUST go through the
134
+ ``show_access_token`` recipe. Without it the patch silently
135
+ regresses to the env-var-only path on sf CLI versions that
136
+ already shipped the dedicated command."""
137
+ recipes_called: list[str] = []
138
+
139
+ def fake_run_sf(name, **params):
140
+ recipes_called.append(name)
141
+ if name == "org_display":
142
+ return _display_payload()
143
+ if name == "show_access_token":
144
+ return _show_token_payload()
145
+ raise AssertionError(f"unexpected recipe: {name}")
146
+
147
+ with mock.patch.object(main, "run_sf", side_effect=fake_run_sf):
148
+ main._resolve_creds("my-org")
149
+
150
+ self.assertIn("show_access_token", recipes_called)
151
+ # And the alias was passed through:
152
+ # (We don't capture params here, but the recipe loader enforces
153
+ # required_params at run_sf time — see test_sf_cli.py.)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ unittest.main()
@@ -0,0 +1,145 @@
1
+ """Tests for resolve_invocation_target.resolve_target_id never raises,
2
+ and `resolve_or_unresolved` records unknown prefixes + invalid shapes into
3
+ `_unresolved[]` so the wave orchestrator can keep running when Salesforce
4
+ ships a new NGA target type.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import unittest
9
+
10
+ from . import _bootstrap # noqa: F401
11
+
12
+ import resolve_invocation_target as rit # type: ignore
13
+
14
+
15
+ # A valid-shape Salesforce Id is 15 or 18 alphanumeric chars. Prefixes below
16
+ # are chosen to avoid collision with _PREFIX_MAP so they exercise the
17
+ # "unknown prefix" path.
18
+ _APEX_ID_15 = "01p0000000ABC12"
19
+ _APEX_ID_18 = "01p0000000ABC12AAA"
20
+ _FLOW_DEF_ID_15 = "3000000000XYZ99"
21
+ _FLOW_VER_ID_15 = "3010000000XYZ99"
22
+ _PROMPT_ID_15 = "0hf0000000QRS77"
23
+ _UNKNOWN_PREFIX_ID_15 = "0aN000000000XYZ"
24
+
25
+
26
+ class KnownPrefixTests(unittest.TestCase):
27
+ def test_apex_prefix(self):
28
+ self.assertEqual(rit.resolve_target_id(_APEX_ID_15), ("apex", "tooling_soql"))
29
+
30
+ def test_flow_definition_prefix(self):
31
+ self.assertEqual(
32
+ rit.resolve_target_id(_FLOW_DEF_ID_15),
33
+ ("flow_definition", "tooling_soql"),
34
+ )
35
+
36
+ def test_flow_version_prefix(self):
37
+ self.assertEqual(
38
+ rit.resolve_target_id(_FLOW_VER_ID_15),
39
+ ("flow_version", "tooling_soql"),
40
+ )
41
+
42
+ def test_prompt_template_prefix(self):
43
+ self.assertEqual(
44
+ rit.resolve_target_id(_PROMPT_ID_15),
45
+ ("prompt_template", "retrieve_required"),
46
+ )
47
+
48
+ def test_eighteen_char_id_works(self):
49
+ self.assertEqual(
50
+ rit.resolve_target_id(_APEX_ID_18),
51
+ ("apex", "tooling_soql"),
52
+ )
53
+
54
+
55
+ class UnknownPrefixTests(unittest.TestCase):
56
+ def test_resolve_target_id_never_raises(self):
57
+ # Unknown prefix → ("unknown", "skip"), no exception.
58
+ self.assertEqual(
59
+ rit.resolve_target_id(_UNKNOWN_PREFIX_ID_15),
60
+ ("unknown", "skip"),
61
+ )
62
+
63
+ def test_resolve_or_unresolved_records_unknown_prefix(self):
64
+ unresolved: list[dict] = []
65
+ result = rit.resolve_or_unresolved(_UNKNOWN_PREFIX_ID_15, unresolved)
66
+ self.assertEqual(result, ("unknown", "skip"))
67
+ self.assertEqual(len(unresolved), 1)
68
+ entry = unresolved[0]
69
+ self.assertEqual(entry["id"], _UNKNOWN_PREFIX_ID_15)
70
+ self.assertEqual(entry["reason"], "unknown-id-prefix:0aN")
71
+
72
+ def test_known_prefix_does_not_touch_unresolved(self):
73
+ unresolved: list[dict] = []
74
+ result = rit.resolve_or_unresolved(_APEX_ID_15, unresolved)
75
+ self.assertEqual(result, ("apex", "tooling_soql"))
76
+ self.assertEqual(unresolved, [])
77
+
78
+
79
+ class InvalidShapeTests(unittest.TestCase):
80
+ def test_empty_string(self):
81
+ unresolved: list[dict] = []
82
+ result = rit.resolve_or_unresolved("", unresolved)
83
+ self.assertEqual(result, ("unknown", "skip"))
84
+ self.assertEqual(len(unresolved), 1)
85
+ self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
86
+ self.assertEqual(unresolved[0]["id"], "")
87
+
88
+ def test_none_coerced_via_str(self):
89
+ unresolved: list[dict] = []
90
+ result = rit.resolve_or_unresolved(None, unresolved)
91
+ self.assertEqual(result, ("unknown", "skip"))
92
+ self.assertEqual(len(unresolved), 1)
93
+ self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
94
+ self.assertEqual(unresolved[0]["id"], "None")
95
+
96
+ def test_wrong_length_is_invalid(self):
97
+ # A 10-char id-like string is not 15 or 18 — invalid shape, not
98
+ # an unknown prefix.
99
+ unresolved: list[dict] = []
100
+ rit.resolve_or_unresolved("01pABC1234", unresolved)
101
+ self.assertEqual(len(unresolved), 1)
102
+ self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
103
+
104
+ def test_bad_chars_rejected(self):
105
+ # 15-char length but contains punctuation — not an Id shape.
106
+ unresolved: list[dict] = []
107
+ rit.resolve_or_unresolved("01p!!!!!!!!!!99", unresolved)
108
+ self.assertEqual(len(unresolved), 1)
109
+ self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
110
+
111
+ def test_short_string_is_invalid(self):
112
+ unresolved: list[dict] = []
113
+ rit.resolve_or_unresolved("ab", unresolved)
114
+ self.assertEqual(len(unresolved), 1)
115
+ self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
116
+
117
+
118
+ class RegisteredPrefixesTests(unittest.TestCase):
119
+ def test_exact_membership(self):
120
+ self.assertEqual(
121
+ rit.REGISTERED_PREFIXES,
122
+ frozenset({"01p", "300", "301", "0hf"}),
123
+ )
124
+
125
+ def test_is_frozenset(self):
126
+ """Immutable so callers can't accidentally corrupt the table."""
127
+ self.assertIsInstance(rit.REGISTERED_PREFIXES, frozenset)
128
+
129
+
130
+ class ResolveTargetIdRobustnessTests(unittest.TestCase):
131
+ """`resolve_target_id` is the lower-level helper — it must also never
132
+ raise, even on garbage input."""
133
+
134
+ def test_none_input(self):
135
+ self.assertEqual(rit.resolve_target_id(None), ("unknown", "skip")) # type: ignore[arg-type]
136
+
137
+ def test_empty_string(self):
138
+ self.assertEqual(rit.resolve_target_id(""), ("unknown", "skip"))
139
+
140
+ def test_too_short(self):
141
+ self.assertEqual(rit.resolve_target_id("ab"), ("unknown", "skip"))
142
+
143
+
144
+ if __name__ == "__main__":
145
+ unittest.main()