@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,247 @@
1
+ """End-to-end integration tests for ``assemble_dc.assemble``.
2
+
3
+ Drives the full assembler against the synthetic session fixture under
4
+ ``tests/fixtures/synthetic_session.py``. Each test materializes the
5
+ fixture into a tmp DATA_ROOT, calls ``assemble_dc.assemble(SID)``, and
6
+ asserts on the resulting tree.
7
+
8
+ These tests cover the orchestration paths that the helper-only
9
+ ``test_assemble_dc_helpers.py`` doesn't touch:
10
+
11
+ - declared Step → Generation → Response → Request chain
12
+ - timestamp-window fallback for an un-declared gateway request
13
+ - trace_id extraction from HTML-escaped AttributeText
14
+ - session-identity resolution from AGENT participant
15
+ - malformed dc.<name>.json → parse_warnings recorded, fixture survives
16
+ - minimal-tree path when sessions[] is empty (session_not_found)
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ import unittest
22
+ from pathlib import Path
23
+ from tempfile import TemporaryDirectory
24
+ from unittest import mock
25
+
26
+ from . import _bootstrap # noqa: F401 — sys.path setup
27
+
28
+ import assemble_dc # type: ignore
29
+ from config import paths # type: ignore
30
+ from .fixtures.synthetic_session import ( # type: ignore
31
+ IDS, make_rows, write_to_disk, session_dir_for,
32
+ )
33
+
34
+
35
+ # -----------------------------------------------------------------------------
36
+ # Helpers
37
+ # -----------------------------------------------------------------------------
38
+
39
+
40
+ class _AssembleHarness:
41
+ """Context-manager that builds a tmp DATA_ROOT, materializes the
42
+ fixture, patches ``paths.DATA_ROOT``, and yields ``(tree, sdir)``."""
43
+
44
+ def __init__(self, mutate_files=None):
45
+ self.mutate_files = mutate_files
46
+
47
+ def __enter__(self):
48
+ self._tmp = TemporaryDirectory()
49
+ self._tmpdir = Path(self._tmp.name)
50
+ sdir = write_to_disk(self._tmpdir)
51
+ if self.mutate_files:
52
+ self.mutate_files(sdir)
53
+ self._patch = mock.patch.object(paths, "DATA_ROOT", self._tmpdir)
54
+ self._patch.start()
55
+ self.tree, self.sdir = assemble_dc.assemble(IDS.SID)
56
+ return self
57
+
58
+ def __exit__(self, *exc):
59
+ self._patch.stop()
60
+ self._tmp.cleanup()
61
+
62
+
63
+ def _turn(tree: dict) -> dict:
64
+ return next(
65
+ iv for iv in tree["session"]["interactions"]
66
+ if iv.get("type") == "TURN"
67
+ )
68
+
69
+
70
+ # -----------------------------------------------------------------------------
71
+ # Top-level shape
72
+ # -----------------------------------------------------------------------------
73
+
74
+
75
+ class AssembleTreeShapeTests(unittest.TestCase):
76
+
77
+ def test_tree_top_level_keys(self):
78
+ with _AssembleHarness() as h:
79
+ self.assertIn("identity", h.tree)
80
+ self.assertIn("session", h.tree)
81
+ self.assertIn("catalog", h.tree)
82
+
83
+ def test_session_dir_path_is_under_data_root(self):
84
+ with _AssembleHarness() as h:
85
+ # On macOS the tmp path resolves through /private/var → /var
86
+ # (or vice versa). Compare via .resolve() so the symlink
87
+ # discrepancy doesn't fail the assertion.
88
+ expected = session_dir_for(h._tmpdir).resolve()
89
+ self.assertEqual(h.sdir.resolve(), expected)
90
+
91
+ def test_three_interactions_in_chronological_order(self):
92
+ with _AssembleHarness() as h:
93
+ ivs = h.tree["session"]["interactions"]
94
+ types = [iv["type"] for iv in ivs]
95
+ self.assertEqual(types, ["SESSION_START", "TURN", "SESSION_END"])
96
+
97
+ def test_turn_has_three_steps_in_order(self):
98
+ with _AssembleHarness() as h:
99
+ turn = _turn(h.tree)
100
+ names = [s.get("name") for s in turn["steps"]]
101
+ # Step names from the fixture's ssot__Name__c column
102
+ self.assertIn("TopicSelection", names)
103
+ self.assertIn("PrimaryAction", names)
104
+ self.assertIn("FinalGuard", names)
105
+
106
+ def test_turn_has_two_messages_user_and_agent(self):
107
+ with _AssembleHarness() as h:
108
+ turn = _turn(h.tree)
109
+ self.assertEqual(len(turn["messages"]), 2)
110
+
111
+
112
+ # -----------------------------------------------------------------------------
113
+ # Identity resolution
114
+ # -----------------------------------------------------------------------------
115
+
116
+
117
+ class AssembleIdentityTests(unittest.TestCase):
118
+
119
+ def test_identity_extracted_from_agent_participant(self):
120
+ with _AssembleHarness() as h:
121
+ ident = h.tree["identity"]
122
+ self.assertEqual(ident["org_id_15"], IDS.ORG_ID_15)
123
+ self.assertEqual(ident["agent_api_name"], IDS.AGENT_API)
124
+ self.assertEqual(ident["agent_version"], IDS.AGENT_VERSION)
125
+
126
+
127
+ # -----------------------------------------------------------------------------
128
+ # Trace_id extraction (HTML-escaped fallback)
129
+ # -----------------------------------------------------------------------------
130
+
131
+
132
+ class AssembleTraceIdTests(unittest.TestCase):
133
+
134
+ def test_turn_trace_id_pulled_from_html_escaped_attribute_text(self):
135
+ with _AssembleHarness() as h:
136
+ turn = _turn(h.tree)
137
+ # The fixture intentionally puts trace_id ONLY in AttributeText
138
+ # (HTML-escaped JSON); the primary TelemetryTraceId__c column is
139
+ # empty. This exercises the fallback path in assemble_dc.
140
+ self.assertEqual(turn["trace_id"], IDS.TRACE_ID)
141
+
142
+
143
+ # -----------------------------------------------------------------------------
144
+ # Gateway binding (declared chain + timestamp-window fallback)
145
+ # -----------------------------------------------------------------------------
146
+
147
+
148
+ class AssembleGatewayBindingTests(unittest.TestCase):
149
+
150
+ def test_action_step_has_declared_gateway_request(self):
151
+ with _AssembleHarness() as h:
152
+ turn = _turn(h.tree)
153
+ action_step = next(
154
+ s for s in turn["steps"] if s.get("name") == "PrimaryAction"
155
+ )
156
+ gw = action_step["gateway_request"]
157
+ self.assertIsNotNone(gw)
158
+ self.assertEqual(gw["binding_method"], "declared")
159
+ self.assertEqual(gw["gateway_request_id"], IDS.GW_REQ_DECLARED)
160
+ self.assertEqual(gw["model"], "gpt-4o")
161
+ self.assertEqual(gw["total_tokens"], 1250)
162
+
163
+ def test_topic_and_guardrail_steps_have_no_gateway_binding(self):
164
+ with _AssembleHarness() as h:
165
+ turn = _turn(h.tree)
166
+ for s in turn["steps"]:
167
+ if s.get("name") in ("TopicSelection", "FinalGuard"):
168
+ self.assertIsNone(s.get("gateway_request"))
169
+
170
+ def test_timestamp_window_pass_picks_up_undeclared_gateway_request(self):
171
+ with _AssembleHarness() as h:
172
+ turn = _turn(h.tree)
173
+ ts_calls = turn.get("timestamp_bound_gateway_calls", [])
174
+ # Exactly one gateway request lives in the TURN window without a
175
+ # declared binding (GW_REQ_WINDOW). The declared one is consumed
176
+ # by step-action and is excluded from the ts-window pass.
177
+ self.assertEqual(len(ts_calls), 1)
178
+ self.assertEqual(
179
+ ts_calls[0]["gateway_request_id"], IDS.GW_REQ_WINDOW,
180
+ )
181
+
182
+ def test_declared_response_carries_finish_reason(self):
183
+ with _AssembleHarness() as h:
184
+ turn = _turn(h.tree)
185
+ action_step = next(
186
+ s for s in turn["steps"] if s.get("name") == "PrimaryAction"
187
+ )
188
+ # parameters__c is HTML-escaped JSON in the fixture; the
189
+ # renderer is responsible for decoding, but the raw string
190
+ # must be preserved unchanged in the assembled tree.
191
+ params = action_step["gateway_request"]["response"]["parameters__c"]
192
+ self.assertIn("finish_reason", params)
193
+ self.assertIn("&quot;", params)
194
+
195
+
196
+ # -----------------------------------------------------------------------------
197
+ # Malformed-input tolerance (parse_warnings)
198
+ # -----------------------------------------------------------------------------
199
+
200
+
201
+ class AssembleParseWarningsTests(unittest.TestCase):
202
+
203
+ def test_malformed_dc_file_recorded_in_parse_warnings(self):
204
+ def corrupt_messages(sdir: Path) -> None:
205
+ (sdir / "dc.messages.json").write_text("<<<not json>>>")
206
+
207
+ with _AssembleHarness(mutate_files=corrupt_messages) as h:
208
+ # parse_warnings lives on session.counts (cf. _build_counts).
209
+ warnings = h.tree["session"]["counts"].get("parse_warnings") or []
210
+ self.assertIn("messages", warnings)
211
+
212
+
213
+ # -----------------------------------------------------------------------------
214
+ # session_not_found short-circuit
215
+ # -----------------------------------------------------------------------------
216
+
217
+
218
+ class AssembleSessionNotFoundTests(unittest.TestCase):
219
+
220
+ def test_empty_sessions_returns_minimal_tree(self):
221
+ def empty_sessions(sdir: Path) -> None:
222
+ (sdir / "dc.sessions.json").write_text("[]")
223
+
224
+ with _AssembleHarness(mutate_files=empty_sessions) as h:
225
+ tree = h.tree
226
+ # Minimal-tree shape signaled by session_shape == 'session_not_found'
227
+ # in the manifest section, plus an empty interactions list.
228
+ self.assertEqual(tree["session"].get("interactions", []), [])
229
+
230
+
231
+ # -----------------------------------------------------------------------------
232
+ # Public API path: tree dict is JSON-serializable
233
+ # -----------------------------------------------------------------------------
234
+
235
+
236
+ class AssembleSerializableTests(unittest.TestCase):
237
+
238
+ def test_tree_round_trips_through_json(self):
239
+ with _AssembleHarness() as h:
240
+ blob = json.dumps(h.tree, default=str)
241
+ back = json.loads(blob)
242
+ # Sanity: re-loaded keys match originals
243
+ self.assertEqual(set(back.keys()), set(h.tree.keys()))
244
+
245
+
246
+ if __name__ == "__main__":
247
+ unittest.main()
@@ -0,0 +1,433 @@
1
+ """Tests for ``dc`` (Data Cloud transport) + ``resolve_session``
2
+ (messaging-id → UUID resolver).
3
+
4
+ Both modules sit at the bottom of the dependency tree and have small,
5
+ well-defined public APIs that are mostly mockable at the subprocess /
6
+ urllib boundary.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import io
11
+ import json
12
+ import subprocess
13
+ import unittest
14
+ import urllib.error
15
+ from pathlib import Path
16
+ from tempfile import TemporaryDirectory
17
+ from types import SimpleNamespace
18
+ from unittest import mock
19
+
20
+ from . import _bootstrap # noqa: F401 — sys.path setup
21
+
22
+ import dc # type: ignore
23
+ import resolve_session # type: ignore
24
+ from config import paths # type: ignore
25
+ from .fixtures.synthetic_session import IDS, write_to_disk # type: ignore
26
+
27
+
28
+ # -----------------------------------------------------------------------------
29
+ # dc.load_sql / dc.parse
30
+ # -----------------------------------------------------------------------------
31
+
32
+
33
+ class LoadSqlTests(unittest.TestCase):
34
+
35
+ def test_substitutes_placeholders_and_strips(self):
36
+ # discover_sessions has SELECT_LIST/JOINS/WHERE_CLAUSE/LIMIT placeholders.
37
+ sql = dc.load_sql(
38
+ "discover_sessions",
39
+ SELECT_LIST="*",
40
+ JOINS="",
41
+ WHERE_CLAUSE="1=1",
42
+ LIMIT="10",
43
+ )
44
+ self.assertIn("SELECT *", sql)
45
+ self.assertIn("LIMIT 10", sql)
46
+
47
+
48
+ class ParseTests(unittest.TestCase):
49
+
50
+ def test_returns_data_array(self):
51
+ self.assertEqual(dc.parse({"data": [{"a": 1}]}), [{"a": 1}])
52
+
53
+ def test_returns_empty_list_when_data_missing(self):
54
+ self.assertEqual(dc.parse({}), [])
55
+
56
+ def test_returns_empty_list_for_falsy_input(self):
57
+ self.assertEqual(dc.parse(None), [])
58
+ self.assertEqual(dc.parse({}), [])
59
+
60
+
61
+ # -----------------------------------------------------------------------------
62
+ # dc.resolve_org — sf CLI shell-out
63
+ # -----------------------------------------------------------------------------
64
+
65
+
66
+ class ResolveOrgTests(unittest.TestCase):
67
+ """Tests for the two-path access-token retrieval per forcedotcom/cli#3560.
68
+
69
+ Path 1 (primary): ``sf org auth show-access-token --json --no-prompt``
70
+ Path 2 (fallback): ``sf org display`` + ``SF_TEMP_SHOW_SECRETS=true``
71
+
72
+ Most tests mock ``subprocess.run`` with a side-effect callable that
73
+ returns a different stub depending on which sf subcommand was invoked,
74
+ so we can exercise primary success, primary failure → fallback, and
75
+ full-failure paths without spawning real processes.
76
+ """
77
+
78
+ REDACTED_TOKEN = "[REDACTED] Use 'sf org auth show-access-token' to view"
79
+
80
+ def _cp(self, stdout: str, *, returncode: int = 0, stderr: str = ""):
81
+ return SimpleNamespace(
82
+ returncode=returncode, stdout=stdout, stderr=stderr,
83
+ )
84
+
85
+ def _display_payload(self, *, access_token: str = "TOKEN_FROM_DISPLAY") -> str:
86
+ return json.dumps({"result": {
87
+ "instanceUrl": "https://example.salesforce.com",
88
+ "accessToken": access_token,
89
+ }})
90
+
91
+ def _show_token_payload(self, *, access_token: str = "TOKEN_FROM_SHOW") -> str:
92
+ return json.dumps({"result": {"accessToken": access_token}})
93
+
94
+ def _route(self, primary_ok=True, primary_unknown=False,
95
+ primary_redacted=False, display_redacted=False):
96
+ """Build a fake_run that routes by argv shape.
97
+
98
+ - primary_ok=True → show-access-token returns clean token
99
+ - primary_unknown → show-access-token raises CalledProcessError
100
+ (older sf CLI without the subcommand)
101
+ - primary_redacted → show-access-token returns the placeholder
102
+ - display_redacted → org_display token field is the placeholder
103
+ (so fallback also fails — test full-failure)
104
+ """
105
+ def fake_run(argv, **kwargs):
106
+ # display call
107
+ if "display" in argv:
108
+ return self._cp(
109
+ self._display_payload(
110
+ access_token=(self.REDACTED_TOKEN if display_redacted
111
+ else "TOKEN_FROM_DISPLAY"),
112
+ ),
113
+ )
114
+ # show-access-token call
115
+ if "show-access-token" in argv:
116
+ if primary_unknown:
117
+ raise subprocess.CalledProcessError(
118
+ returncode=1, cmd=argv,
119
+ stderr="show-access-token is not a sf command",
120
+ )
121
+ token = (self.REDACTED_TOKEN if primary_redacted
122
+ else "TOKEN_FROM_SHOW")
123
+ return self._cp(self._show_token_payload(access_token=token))
124
+ raise AssertionError(f"unexpected argv: {argv}")
125
+ return fake_run
126
+
127
+ def test_primary_path_returns_show_token(self):
128
+ """Happy path — dedicated command returns a clean token."""
129
+ with mock.patch.object(dc.subprocess, "run", side_effect=self._route()):
130
+ url, token = dc.resolve_org("my-org")
131
+ self.assertEqual(url, "https://example.salesforce.com")
132
+ self.assertEqual(token, "TOKEN_FROM_SHOW")
133
+
134
+ def test_primary_unknown_falls_back_to_display_token(self):
135
+ """Older sf CLI: show-access-token unknown → use display payload."""
136
+ with mock.patch.object(
137
+ dc.subprocess, "run",
138
+ side_effect=self._route(primary_unknown=True),
139
+ ):
140
+ url, token = dc.resolve_org("my-org")
141
+ self.assertEqual(url, "https://example.salesforce.com")
142
+ self.assertEqual(token, "TOKEN_FROM_DISPLAY")
143
+
144
+ def test_primary_redacted_falls_back_to_display_token(self):
145
+ """Edge case: dedicated command returns the placeholder string —
146
+ treat as failure and try the display fallback."""
147
+ with mock.patch.object(
148
+ dc.subprocess, "run",
149
+ side_effect=self._route(primary_redacted=True),
150
+ ):
151
+ url, token = dc.resolve_org("my-org")
152
+ self.assertEqual(token, "TOKEN_FROM_DISPLAY")
153
+
154
+ def test_both_paths_redacted_raises(self):
155
+ """If both paths return the placeholder, surface a clean SystemExit
156
+ rather than handing back the redaction string to downstream callers
157
+ (which would cause INVALID_AUTH_HEADER 401 on every Tooling/REST call)."""
158
+ with mock.patch.object(
159
+ dc.subprocess, "run",
160
+ side_effect=self._route(primary_redacted=True, display_redacted=True),
161
+ ):
162
+ with self.assertRaises(SystemExit) as ctx:
163
+ dc.resolve_org("my-org")
164
+ self.assertIn("could not retrieve a usable access token", str(ctx.exception))
165
+
166
+ def test_raises_systemexit_when_sf_cli_missing(self):
167
+ """sf binary not on PATH — bail with the upgrade hint."""
168
+ with mock.patch.object(
169
+ dc.subprocess, "run", side_effect=FileNotFoundError("sf"),
170
+ ):
171
+ with self.assertRaises(SystemExit) as ctx:
172
+ dc.resolve_org("my-org")
173
+ self.assertIn("sf CLI not found", str(ctx.exception))
174
+
175
+ def test_raises_systemexit_on_display_failure(self):
176
+ """org_display itself failing is fatal — no instanceUrl, no recovery."""
177
+ err = subprocess.CalledProcessError(
178
+ returncode=1, cmd=["sf", "org", "display"], stderr="No AuthInfo found",
179
+ )
180
+ with mock.patch.object(dc.subprocess, "run", side_effect=err):
181
+ with self.assertRaises(SystemExit):
182
+ dc.resolve_org("my-org")
183
+
184
+ def test_primary_path_argv_contains_show_access_token(self):
185
+ """Tripwire — primary call MUST be `sf org auth show-access-token`
186
+ with `--no-prompt`. Without `--no-prompt` the command blocks on a
187
+ confirmation banner that --json doesn't suppress on its own."""
188
+ captured_argvs: list[list[str]] = []
189
+
190
+ def fake_run(argv, **kwargs):
191
+ captured_argvs.append(argv)
192
+ if "display" in argv:
193
+ return self._cp(self._display_payload())
194
+ return self._cp(self._show_token_payload())
195
+
196
+ with mock.patch.object(dc.subprocess, "run", side_effect=fake_run):
197
+ dc.resolve_org("my-org")
198
+
199
+ # display call should still pass --verbose + SF_TEMP_SHOW_SECRETS
200
+ # (so the fallback path stays viable on this same invocation).
201
+ self.assertTrue(any("display" in a for a in captured_argvs))
202
+ # primary call shape:
203
+ primary = next(a for a in captured_argvs if "show-access-token" in a)
204
+ self.assertIn("--no-prompt", primary)
205
+ self.assertIn("--json", primary)
206
+ self.assertIn("--target-org", primary)
207
+
208
+ def test_display_call_still_passes_verbose_and_show_secrets_env(self):
209
+ """The legacy fallback path stays armed: org_display still runs
210
+ with `--verbose` (so accessToken is emitted) and
211
+ `SF_TEMP_SHOW_SECRETS=true` (so the token isn't redacted on sf
212
+ CLI versions that still honour the workaround)."""
213
+ captured = {}
214
+
215
+ def fake_run(argv, **kwargs):
216
+ if "display" in argv:
217
+ captured["argv"] = argv
218
+ captured["env"] = kwargs.get("env")
219
+ return self._cp(self._display_payload())
220
+ return self._cp(self._show_token_payload())
221
+
222
+ with mock.patch.object(dc.subprocess, "run", side_effect=fake_run):
223
+ dc.resolve_org("my-org")
224
+
225
+ self.assertIn("--verbose", captured["argv"])
226
+ self.assertIsNotNone(captured["env"])
227
+ self.assertEqual(captured["env"].get("SF_TEMP_SHOW_SECRETS"), "true")
228
+
229
+
230
+ # -----------------------------------------------------------------------------
231
+ # dc.post — HTTP path (urllib mock)
232
+ # -----------------------------------------------------------------------------
233
+
234
+
235
+ class PostTests(unittest.TestCase):
236
+
237
+ def _fake_response(self, body: bytes):
238
+ # Context-manager mock for urllib.request.urlopen
239
+ cm = mock.MagicMock()
240
+ cm.__enter__.return_value.read.return_value = body
241
+ cm.__exit__.return_value = False
242
+ return cm
243
+
244
+ def test_returns_rows_on_2xx(self):
245
+ body = json.dumps({"data": [{"a": 1}, {"a": 2}]}).encode()
246
+ with mock.patch.object(
247
+ dc.urllib.request, "urlopen", return_value=self._fake_response(body),
248
+ ):
249
+ out = dc.post(
250
+ "SELECT 1", "https://x.salesforce.com", "TOKEN", "sessions",
251
+ )
252
+ self.assertEqual(out, [{"a": 1}, {"a": 2}])
253
+
254
+ def test_raises_dcqueryerror_with_query_name_on_http_error(self):
255
+ # HTTPError carries (url, code, msg, hdrs, fp). We need fp.read() to
256
+ # work — the impl calls e.read() to grab the body.
257
+ err = urllib.error.HTTPError(
258
+ url="https://x.salesforce.com",
259
+ code=400, msg="Bad Request",
260
+ hdrs=None,
261
+ fp=io.BytesIO(b"sql parse error: missing FROM"),
262
+ )
263
+ with mock.patch.object(
264
+ dc.urllib.request, "urlopen", side_effect=err,
265
+ ):
266
+ with self.assertRaises(dc.DCQueryError) as ctx:
267
+ dc.post("SELECT bad", "https://x", "TOKEN", "sessions")
268
+ msg = str(ctx.exception)
269
+ self.assertIn("sessions", msg)
270
+ self.assertIn("http=400", msg)
271
+ self.assertIn("sql parse error", msg)
272
+
273
+
274
+ # -----------------------------------------------------------------------------
275
+ # resolve_session.is_messaging_id — pure shape check
276
+ # -----------------------------------------------------------------------------
277
+
278
+
279
+ class IsMessagingIdTests(unittest.TestCase):
280
+
281
+ def test_15_char_0Mw_prefix_matches(self):
282
+ self.assertTrue(resolve_session.is_messaging_id("0MwTESTMSG12345"))
283
+
284
+ def test_18_char_0Mw_prefix_matches(self):
285
+ self.assertTrue(resolve_session.is_messaging_id("0MwTESTMSG12345AAA"))
286
+
287
+ def test_uuid_does_not_match(self):
288
+ # 36 chars, dashes — UUIDs never accidentally pass.
289
+ self.assertFalse(resolve_session.is_messaging_id(IDS.SID))
290
+
291
+ def test_empty_does_not_match(self):
292
+ self.assertFalse(resolve_session.is_messaging_id(""))
293
+
294
+ def test_wrong_prefix_does_not_match(self):
295
+ self.assertFalse(resolve_session.is_messaging_id("FOOVF00000AtTbV"))
296
+
297
+
298
+ # -----------------------------------------------------------------------------
299
+ # resolve_session.resolve_from_disk — scans DATA_ROOT
300
+ # -----------------------------------------------------------------------------
301
+
302
+
303
+ class ResolveFromDiskTests(unittest.TestCase):
304
+
305
+ def test_uuid_input_passes_through_unchanged(self):
306
+ self.assertEqual(
307
+ resolve_session.resolve_from_disk(IDS.SID), IDS.SID,
308
+ )
309
+
310
+ def test_finds_uuid_when_messaging_id_in_dc_sessions(self):
311
+ with TemporaryDirectory() as t:
312
+ tmp = Path(t)
313
+ write_to_disk(tmp) # synthetic fixture has the messaging id wired
314
+ with mock.patch.object(
315
+ resolve_session, "DATA_ROOT", tmp,
316
+ ):
317
+ out = resolve_session.resolve_from_disk("0MwTESTMSG12345AAA")
318
+ self.assertEqual(out, IDS.SID)
319
+
320
+ def test_returns_none_when_messaging_id_not_present_on_disk(self):
321
+ with TemporaryDirectory() as t:
322
+ tmp = Path(t)
323
+ write_to_disk(tmp)
324
+ with mock.patch.object(
325
+ resolve_session, "DATA_ROOT", tmp,
326
+ ):
327
+ out = resolve_session.resolve_from_disk("0Mw000000000000")
328
+ self.assertIsNone(out)
329
+
330
+ def test_returns_none_when_data_root_missing(self):
331
+ with TemporaryDirectory() as t:
332
+ ghost = Path(t) / "no-such"
333
+ with mock.patch.object(
334
+ resolve_session, "DATA_ROOT", ghost,
335
+ ):
336
+ out = resolve_session.resolve_from_disk("0MwTESTMSG12345AAA")
337
+ self.assertIsNone(out)
338
+
339
+ def test_skips_archive_dirs(self):
340
+ # Plant a duplicate inside an "<uuid> - archive 1" dir; the resolver
341
+ # should ignore it. Without the skip, the extra row could trigger
342
+ # spurious multi-match.
343
+ with TemporaryDirectory() as t:
344
+ tmp = Path(t)
345
+ write_to_disk(tmp)
346
+ archive = tmp / IDS.ORG_ID_15 / f"{IDS.AGENT_API}__{IDS.AGENT_VERSION}" / f"{IDS.SID} - archive 1"
347
+ archive.mkdir(parents=True)
348
+ (archive / "dc.sessions.json").write_text(json.dumps([{
349
+ "ssot__Id__c": "different-uuid-but-same-msg",
350
+ "ssot__RelatedMessagingSessionId__c": "0MwTESTMSG12345AAA",
351
+ }]))
352
+ with mock.patch.object(resolve_session, "DATA_ROOT", tmp):
353
+ out = resolve_session.resolve_from_disk("0MwTESTMSG12345AAA")
354
+ # Resolver should return the canonical UUID, ignoring the archive
355
+ # row. (If the archive weren't skipped, this would multi-match
356
+ # raise.)
357
+ self.assertEqual(out, IDS.SID)
358
+
359
+
360
+ # -----------------------------------------------------------------------------
361
+ # resolve_session.resolve_disk_or_live — combined path
362
+ # -----------------------------------------------------------------------------
363
+
364
+
365
+ class ResolveDiskOrLiveTests(unittest.TestCase):
366
+
367
+ def test_uuid_input_passes_through(self):
368
+ self.assertEqual(
369
+ resolve_session.resolve_disk_or_live(IDS.SID), IDS.SID,
370
+ )
371
+
372
+ def test_disk_hit_returns_uuid_without_dc_call(self):
373
+ with TemporaryDirectory() as t:
374
+ tmp = Path(t)
375
+ write_to_disk(tmp)
376
+ with mock.patch.object(resolve_session, "DATA_ROOT", tmp):
377
+ with mock.patch.object(resolve_session, "_live_lookup") as live:
378
+ out = resolve_session.resolve_disk_or_live(
379
+ "0MwTESTMSG12345AAA", org="my-org",
380
+ )
381
+ live.assert_not_called()
382
+ self.assertEqual(out, IDS.SID)
383
+
384
+ def test_disk_miss_no_org_raises_with_hint(self):
385
+ with TemporaryDirectory() as t:
386
+ tmp = Path(t)
387
+ with mock.patch.object(resolve_session, "DATA_ROOT", tmp):
388
+ with self.assertRaises(SystemExit) as ctx:
389
+ resolve_session.resolve_disk_or_live(
390
+ "0MwTESTMSG12345AAA",
391
+ )
392
+ self.assertIn("cannot resolve messaging id", str(ctx.exception))
393
+
394
+
395
+ # -----------------------------------------------------------------------------
396
+ # resolve_session.resolve — live DC-backed path
397
+ # -----------------------------------------------------------------------------
398
+
399
+
400
+ class ResolveLiveTests(unittest.TestCase):
401
+
402
+ def test_single_row_returns_uuid(self):
403
+ with mock.patch.object(
404
+ resolve_session, "_live_lookup",
405
+ return_value=[{"ssot__Id__c": "uuid-1"}],
406
+ ):
407
+ out = resolve_session.resolve("0MwTESTMSG12345AAA", org="my-org")
408
+ self.assertEqual(out, "uuid-1")
409
+
410
+ def test_zero_rows_raises(self):
411
+ with mock.patch.object(
412
+ resolve_session, "_live_lookup", return_value=[],
413
+ ):
414
+ with self.assertRaises(SystemExit) as ctx:
415
+ resolve_session.resolve("0MwTESTMSG12345AAA", org="my-org")
416
+ self.assertIn("no ssot__AIAgentSession", str(ctx.exception))
417
+
418
+ def test_multi_row_raises_with_candidate_list(self):
419
+ rows = [
420
+ {"ssot__Id__c": "uuid-A", "ssot__StartTimestamp__c": "t"},
421
+ {"ssot__Id__c": "uuid-B", "ssot__StartTimestamp__c": "t"},
422
+ ]
423
+ with mock.patch.object(
424
+ resolve_session, "_live_lookup", return_value=rows,
425
+ ):
426
+ with self.assertRaises(SystemExit) as ctx:
427
+ resolve_session.resolve("0MwTESTMSG12345AAA", org="my-org")
428
+ self.assertIn("uuid-A", str(ctx.exception))
429
+ self.assertIn("uuid-B", str(ctx.exception))
430
+
431
+
432
+ if __name__ == "__main__":
433
+ unittest.main()