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