@salesforce/afv-skills 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- 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-ui-bundle-app/SKILL.md +33 -8
- package/skills/generating-custom-application/SKILL.md +1 -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-ui-bundle-custom-app/SKILL.md +93 -0
- package/skills/generating-ui-bundle-custom-app/docs/configure-metadata-custom-application.md +70 -0
- package/skills/generating-ui-bundle-metadata/SKILL.md +39 -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/reviewing-lwc-mobile-offline/SKILL.md +168 -0
- package/skills/reviewing-lwc-mobile-offline/references/grounding.md +7 -0
- package/skills/reviewing-lwc-mobile-offline/references/inline-graphql.md +43 -0
- package/skills/reviewing-lwc-mobile-offline/references/komaci-eslint.md +125 -0
- package/skills/reviewing-lwc-mobile-offline/references/lwc-if.md +78 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/komaci.config.mjs +18 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/package.json +10 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/run-komaci.sh +69 -0
- 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/using-mobile-native-capabilities/SKILL.md +182 -0
- package/skills/using-mobile-native-capabilities/references/app-review.md +68 -0
- package/skills/using-mobile-native-capabilities/references/ar-space-capture.md +125 -0
- package/skills/using-mobile-native-capabilities/references/barcode-scanner.md +219 -0
- package/skills/using-mobile-native-capabilities/references/base-capability.md +22 -0
- package/skills/using-mobile-native-capabilities/references/biometrics.md +90 -0
- package/skills/using-mobile-native-capabilities/references/calendar.md +213 -0
- package/skills/using-mobile-native-capabilities/references/contacts.md +232 -0
- package/skills/using-mobile-native-capabilities/references/document-scanner.md +342 -0
- package/skills/using-mobile-native-capabilities/references/geofencing.md +123 -0
- package/skills/using-mobile-native-capabilities/references/location.md +158 -0
- package/skills/using-mobile-native-capabilities/references/mobile-capabilities.md +30 -0
- package/skills/using-mobile-native-capabilities/references/nfc.md +181 -0
- package/skills/using-mobile-native-capabilities/references/payments.md +95 -0
- 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,203 @@
|
|
|
1
|
+
"""Tests for ``resolve_bot`` — Bot + version resolution helpers + main flow.
|
|
2
|
+
|
|
3
|
+
Covers the small pure helpers (``scrub``, ``natural_key``,
|
|
4
|
+
``emit_error_block``) plus a happy-path ``main`` end-to-end with
|
|
5
|
+
``subprocess.run`` mocked.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import unittest
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from tempfile import TemporaryDirectory
|
|
14
|
+
from types import SimpleNamespace
|
|
15
|
+
from unittest import mock
|
|
16
|
+
|
|
17
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
18
|
+
|
|
19
|
+
import resolve_bot # type: ignore
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# -----------------------------------------------------------------------------
|
|
23
|
+
# scrub
|
|
24
|
+
# -----------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ScrubTests(unittest.TestCase):
|
|
28
|
+
|
|
29
|
+
def test_strips_dangerous_shell_chars(self):
|
|
30
|
+
# ` $ " \\ \r \t \0 \n all stripped; safe chars kept verbatim.
|
|
31
|
+
self.assertEqual(
|
|
32
|
+
resolve_bot.scrub("hello`bad$\"" + "\n" + "world"),
|
|
33
|
+
"hellobadworld",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def test_strips_carriage_return_and_tab(self):
|
|
37
|
+
self.assertEqual(resolve_bot.scrub("a\tb\rc"), "abc")
|
|
38
|
+
|
|
39
|
+
def test_returns_empty_string_for_none(self):
|
|
40
|
+
self.assertEqual(resolve_bot.scrub(None), "")
|
|
41
|
+
|
|
42
|
+
def test_coerces_non_strings(self):
|
|
43
|
+
self.assertEqual(resolve_bot.scrub(42), "42")
|
|
44
|
+
|
|
45
|
+
def test_passes_safe_chars_through(self):
|
|
46
|
+
self.assertEqual(resolve_bot.scrub("Customer_Support_Agent"),
|
|
47
|
+
"Customer_Support_Agent")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# -----------------------------------------------------------------------------
|
|
51
|
+
# natural_key — version sorting
|
|
52
|
+
# -----------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class NaturalKeyTests(unittest.TestCase):
|
|
56
|
+
|
|
57
|
+
def test_sorts_v10_after_v9(self):
|
|
58
|
+
keys = ["v9", "v10", "v2", "v1"]
|
|
59
|
+
keys.sort(key=resolve_bot.natural_key, reverse=True)
|
|
60
|
+
self.assertEqual(keys, ["v10", "v9", "v2", "v1"])
|
|
61
|
+
|
|
62
|
+
def test_handles_none_and_empty_string(self):
|
|
63
|
+
# Both should be safe (empty list)
|
|
64
|
+
self.assertEqual(resolve_bot.natural_key(""), [""])
|
|
65
|
+
self.assertEqual(resolve_bot.natural_key(None), [""])
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# -----------------------------------------------------------------------------
|
|
69
|
+
# emit_error_block — terminal RESULT block + sys.exit
|
|
70
|
+
# -----------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class EmitErrorBlockTests(unittest.TestCase):
|
|
74
|
+
|
|
75
|
+
def test_emits_result_block_and_exits_one(self):
|
|
76
|
+
old_env = dict(os.environ)
|
|
77
|
+
os.environ["AGENT_API_NAME"] = "MyAgent"
|
|
78
|
+
os.environ["ORG_ID_15"] = "00D000000000000"
|
|
79
|
+
os.environ["ORG_ID_18"] = "00D000000000000EAA"
|
|
80
|
+
os.environ.pop("ERROR_TEE", None)
|
|
81
|
+
try:
|
|
82
|
+
with mock.patch.object(resolve_bot.sys, "stdout") as out:
|
|
83
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
84
|
+
resolve_bot.emit_error_block(
|
|
85
|
+
"AGENT_NOT_FOUND", "details here", {"AVAILABLE_BOTS": "A,B"},
|
|
86
|
+
)
|
|
87
|
+
self.assertEqual(ctx.exception.code, 1)
|
|
88
|
+
written = "".join(c.args[0] for c in out.write.call_args_list)
|
|
89
|
+
self.assertIn("STATUS=AGENT_NOT_FOUND", written)
|
|
90
|
+
self.assertIn("ERROR_DETAIL=details here", written)
|
|
91
|
+
self.assertIn("AGENT_API_NAME=MyAgent", written)
|
|
92
|
+
self.assertIn("AVAILABLE_BOTS=A,B", written)
|
|
93
|
+
finally:
|
|
94
|
+
os.environ.clear()
|
|
95
|
+
os.environ.update(old_env)
|
|
96
|
+
|
|
97
|
+
def test_writes_error_tee_when_env_set(self):
|
|
98
|
+
with TemporaryDirectory() as t:
|
|
99
|
+
tee_path = Path(t) / "subdir" / "tee.txt"
|
|
100
|
+
old_env = dict(os.environ)
|
|
101
|
+
os.environ["ERROR_TEE"] = str(tee_path)
|
|
102
|
+
os.environ["AGENT_API_NAME"] = "MyAgent"
|
|
103
|
+
os.environ["ORG_ID_15"] = "x"
|
|
104
|
+
os.environ["ORG_ID_18"] = "y"
|
|
105
|
+
try:
|
|
106
|
+
with mock.patch.object(resolve_bot.sys, "stdout"):
|
|
107
|
+
with self.assertRaises(SystemExit):
|
|
108
|
+
resolve_bot.emit_error_block("X", "y", {})
|
|
109
|
+
# tee_path got the same content
|
|
110
|
+
self.assertTrue(tee_path.is_file())
|
|
111
|
+
self.assertIn("STATUS=X", tee_path.read_text())
|
|
112
|
+
finally:
|
|
113
|
+
os.environ.clear()
|
|
114
|
+
os.environ.update(old_env)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# -----------------------------------------------------------------------------
|
|
118
|
+
# main — happy path with mocked sf data query
|
|
119
|
+
# -----------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _versions_payload() -> str:
|
|
123
|
+
return json.dumps({
|
|
124
|
+
"result": {
|
|
125
|
+
"records": [
|
|
126
|
+
{"DeveloperName": "v3", "Status": "Active",
|
|
127
|
+
"BotDefinitionId": "0Xx000000000ABC",
|
|
128
|
+
"BotDefinition": {"DeveloperName": "MyAgent",
|
|
129
|
+
"MasterLabel": "My Agent"}},
|
|
130
|
+
{"DeveloperName": "v2", "Status": "Inactive",
|
|
131
|
+
"BotDefinitionId": "0Xx000000000ABC",
|
|
132
|
+
"BotDefinition": {"DeveloperName": "MyAgent",
|
|
133
|
+
"MasterLabel": "My Agent"}},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _bot_def_payload() -> str:
|
|
140
|
+
return json.dumps({
|
|
141
|
+
"result": {
|
|
142
|
+
"records": [
|
|
143
|
+
{"DeveloperName": "MyAgent", "MasterLabel": "My Agent",
|
|
144
|
+
"Description": "demo", "AgentType": "Internal",
|
|
145
|
+
"Type": "AiCopilot", "AgentTemplate": "T",
|
|
146
|
+
"BotSource": "AgentforceAgentCopilot"},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class MainTests(unittest.TestCase):
|
|
153
|
+
|
|
154
|
+
def _run_main(self, *, agent_version: str = "") -> tuple[int, str]:
|
|
155
|
+
old_env = dict(os.environ)
|
|
156
|
+
with TemporaryDirectory() as t:
|
|
157
|
+
tmp = Path(t)
|
|
158
|
+
os.environ["ORG_ALIAS"] = "my-org"
|
|
159
|
+
os.environ["AGENT_API_NAME"] = "MyAgent"
|
|
160
|
+
os.environ["WORK_DIR"] = str(tmp)
|
|
161
|
+
os.environ["AGENT_VERSION"] = agent_version
|
|
162
|
+
|
|
163
|
+
calls: list = []
|
|
164
|
+
|
|
165
|
+
def fake_run(argv, **kw):
|
|
166
|
+
# Two distinct sf data queries: BotVersion then BotDefinition
|
|
167
|
+
calls.append(argv)
|
|
168
|
+
if "BotVersion" in argv[-1]:
|
|
169
|
+
return SimpleNamespace(returncode=0, stdout=_versions_payload(), stderr="")
|
|
170
|
+
if "BotDefinition" in argv[-1]:
|
|
171
|
+
return SimpleNamespace(returncode=0, stdout=_bot_def_payload(), stderr="")
|
|
172
|
+
return SimpleNamespace(returncode=0, stdout="{}", stderr="")
|
|
173
|
+
|
|
174
|
+
stdout_buf: list[str] = []
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
with mock.patch.object(resolve_bot.subprocess, "run", side_effect=fake_run):
|
|
178
|
+
with mock.patch.object(resolve_bot.sys, "stdout") as out:
|
|
179
|
+
out.write = lambda s: stdout_buf.append(s)
|
|
180
|
+
rc = resolve_bot.main()
|
|
181
|
+
finally:
|
|
182
|
+
os.environ.clear()
|
|
183
|
+
os.environ.update(old_env)
|
|
184
|
+
return rc, "".join(stdout_buf)
|
|
185
|
+
|
|
186
|
+
def test_main_succeeds_with_auto_pick(self):
|
|
187
|
+
rc, written = self._run_main()
|
|
188
|
+
self.assertEqual(rc, 0)
|
|
189
|
+
# v3 is Active and lexically highest → auto-picked
|
|
190
|
+
self.assertIn("AGENT_VERSION=v3", written)
|
|
191
|
+
self.assertIn("VERSION_AUTO_PICKED=true", written)
|
|
192
|
+
self.assertIn("BOT_FOUND=true", written)
|
|
193
|
+
self.assertIn("BOT_ID=0Xx000000000ABC", written)
|
|
194
|
+
|
|
195
|
+
def test_main_succeeds_with_explicit_version_match(self):
|
|
196
|
+
rc, written = self._run_main(agent_version="v2")
|
|
197
|
+
self.assertEqual(rc, 0)
|
|
198
|
+
self.assertIn("AGENT_VERSION=v2", written)
|
|
199
|
+
self.assertIn("VERSION_AUTO_PICKED=false", written)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
unittest.main()
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Tests for ``main._resolve_creds`` — the two-path access-token retrieval
|
|
2
|
+
introduced for forcedotcom/cli#3560 (sf CLI v2 redaction, effective
|
|
3
|
+
2026-05-27).
|
|
4
|
+
|
|
5
|
+
Path 1 (primary): ``sf org auth show-access-token --json --no-prompt``
|
|
6
|
+
via the ``show_access_token`` recipe.
|
|
7
|
+
Path 2 (fallback): ``sf org display`` payload with
|
|
8
|
+
``SF_TEMP_SHOW_SECRETS=true`` env var.
|
|
9
|
+
|
|
10
|
+
We mock ``run_sf`` (not subprocess) since these tests target the
|
|
11
|
+
orchestration logic in ``main.py``, not the recipe loader. The recipe
|
|
12
|
+
loader and subprocess env injection have their own coverage in
|
|
13
|
+
``test_sf_cli.py``.
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import unittest
|
|
18
|
+
from unittest import mock
|
|
19
|
+
|
|
20
|
+
from . import _bootstrap # noqa: F401 — sys.path setup
|
|
21
|
+
|
|
22
|
+
import main # type: ignore
|
|
23
|
+
from sf_cli import AuthRequired, SfCliError # type: ignore
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
REDACTED_TOKEN = "[REDACTED] Use 'sf org auth show-access-token' to view"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _display_payload(*, instance_url="https://example.salesforce.com",
|
|
30
|
+
access_token="TOKEN_FROM_DISPLAY"):
|
|
31
|
+
return {"result": {
|
|
32
|
+
"instanceUrl": instance_url,
|
|
33
|
+
"accessToken": access_token,
|
|
34
|
+
}}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _show_token_payload(*, access_token="TOKEN_FROM_SHOW"):
|
|
38
|
+
return {"result": {"accessToken": access_token}}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ResolveCredsTests(unittest.TestCase):
|
|
42
|
+
"""Cover every branch of the two-path retrieval."""
|
|
43
|
+
|
|
44
|
+
def _route(self, *, primary_payload=None, primary_exc=None,
|
|
45
|
+
display_payload=None):
|
|
46
|
+
"""Build a ``run_sf`` side-effect that dispatches by recipe name."""
|
|
47
|
+
display = display_payload or _display_payload()
|
|
48
|
+
primary = primary_payload or _show_token_payload()
|
|
49
|
+
|
|
50
|
+
def fake_run_sf(name, **params):
|
|
51
|
+
if name == "org_display":
|
|
52
|
+
return display
|
|
53
|
+
if name == "show_access_token":
|
|
54
|
+
if primary_exc is not None:
|
|
55
|
+
raise primary_exc
|
|
56
|
+
return primary
|
|
57
|
+
raise AssertionError(f"unexpected recipe: {name}")
|
|
58
|
+
|
|
59
|
+
return fake_run_sf
|
|
60
|
+
|
|
61
|
+
def test_primary_path_returns_show_token(self):
|
|
62
|
+
"""Happy path — dedicated command returns a clean token."""
|
|
63
|
+
with mock.patch.object(main, "run_sf", side_effect=self._route()):
|
|
64
|
+
url, token = main._resolve_creds("my-org")
|
|
65
|
+
self.assertEqual(url, "https://example.salesforce.com")
|
|
66
|
+
self.assertEqual(token, "TOKEN_FROM_SHOW")
|
|
67
|
+
|
|
68
|
+
def test_primary_unknown_falls_back_to_display(self):
|
|
69
|
+
"""Older sf CLI without the dedicated command surfaces SfCliError;
|
|
70
|
+
we fall back to the display payload's accessToken."""
|
|
71
|
+
with mock.patch.object(
|
|
72
|
+
main, "run_sf",
|
|
73
|
+
side_effect=self._route(
|
|
74
|
+
primary_exc=SfCliError("sf CLI 'show_access_token' failed"),
|
|
75
|
+
),
|
|
76
|
+
):
|
|
77
|
+
url, token = main._resolve_creds("my-org")
|
|
78
|
+
self.assertEqual(url, "https://example.salesforce.com")
|
|
79
|
+
self.assertEqual(token, "TOKEN_FROM_DISPLAY")
|
|
80
|
+
|
|
81
|
+
def test_primary_returns_redacted_token_falls_back(self):
|
|
82
|
+
"""Edge case: dedicated command runs cleanly but returns the
|
|
83
|
+
placeholder string. Treat as failure and use the display fallback."""
|
|
84
|
+
with mock.patch.object(
|
|
85
|
+
main, "run_sf",
|
|
86
|
+
side_effect=self._route(
|
|
87
|
+
primary_payload=_show_token_payload(access_token=REDACTED_TOKEN),
|
|
88
|
+
),
|
|
89
|
+
):
|
|
90
|
+
_, token = main._resolve_creds("my-org")
|
|
91
|
+
self.assertEqual(token, "TOKEN_FROM_DISPLAY")
|
|
92
|
+
|
|
93
|
+
def test_primary_returns_empty_token_falls_back(self):
|
|
94
|
+
"""Empty string from the dedicated command also triggers fallback."""
|
|
95
|
+
with mock.patch.object(
|
|
96
|
+
main, "run_sf",
|
|
97
|
+
side_effect=self._route(
|
|
98
|
+
primary_payload=_show_token_payload(access_token=""),
|
|
99
|
+
),
|
|
100
|
+
):
|
|
101
|
+
_, token = main._resolve_creds("my-org")
|
|
102
|
+
self.assertEqual(token, "TOKEN_FROM_DISPLAY")
|
|
103
|
+
|
|
104
|
+
def test_both_paths_redacted_raises_authrequired(self):
|
|
105
|
+
"""If both paths come back redacted/empty, surface AuthRequired
|
|
106
|
+
rather than handing the placeholder to downstream Tooling/REST
|
|
107
|
+
callers (which would 401 with INVALID_AUTH_HEADER)."""
|
|
108
|
+
with mock.patch.object(
|
|
109
|
+
main, "run_sf",
|
|
110
|
+
side_effect=self._route(
|
|
111
|
+
primary_payload=_show_token_payload(access_token=REDACTED_TOKEN),
|
|
112
|
+
display_payload=_display_payload(access_token=REDACTED_TOKEN),
|
|
113
|
+
),
|
|
114
|
+
):
|
|
115
|
+
with self.assertRaises(AuthRequired) as ctx:
|
|
116
|
+
main._resolve_creds("my-org")
|
|
117
|
+
self.assertIn("could not retrieve a usable access token", str(ctx.exception))
|
|
118
|
+
|
|
119
|
+
def test_missing_instance_url_raises_authrequired(self):
|
|
120
|
+
"""display returning empty instanceUrl is a hard failure — no
|
|
121
|
+
amount of token-juggling helps if we can't talk to the org."""
|
|
122
|
+
with mock.patch.object(
|
|
123
|
+
main, "run_sf",
|
|
124
|
+
side_effect=self._route(
|
|
125
|
+
display_payload=_display_payload(instance_url=""),
|
|
126
|
+
),
|
|
127
|
+
):
|
|
128
|
+
with self.assertRaises(AuthRequired) as ctx:
|
|
129
|
+
main._resolve_creds("my-org")
|
|
130
|
+
self.assertIn("instanceUrl", str(ctx.exception))
|
|
131
|
+
|
|
132
|
+
def test_primary_path_recipe_name_is_show_access_token(self):
|
|
133
|
+
"""Tripwire — the primary call MUST go through the
|
|
134
|
+
``show_access_token`` recipe. Without it the patch silently
|
|
135
|
+
regresses to the env-var-only path on sf CLI versions that
|
|
136
|
+
already shipped the dedicated command."""
|
|
137
|
+
recipes_called: list[str] = []
|
|
138
|
+
|
|
139
|
+
def fake_run_sf(name, **params):
|
|
140
|
+
recipes_called.append(name)
|
|
141
|
+
if name == "org_display":
|
|
142
|
+
return _display_payload()
|
|
143
|
+
if name == "show_access_token":
|
|
144
|
+
return _show_token_payload()
|
|
145
|
+
raise AssertionError(f"unexpected recipe: {name}")
|
|
146
|
+
|
|
147
|
+
with mock.patch.object(main, "run_sf", side_effect=fake_run_sf):
|
|
148
|
+
main._resolve_creds("my-org")
|
|
149
|
+
|
|
150
|
+
self.assertIn("show_access_token", recipes_called)
|
|
151
|
+
# And the alias was passed through:
|
|
152
|
+
# (We don't capture params here, but the recipe loader enforces
|
|
153
|
+
# required_params at run_sf time — see test_sf_cli.py.)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
unittest.main()
|
package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Tests for resolve_invocation_target.resolve_target_id never raises,
|
|
2
|
+
and `resolve_or_unresolved` records unknown prefixes + invalid shapes into
|
|
3
|
+
`_unresolved[]` so the wave orchestrator can keep running when Salesforce
|
|
4
|
+
ships a new NGA target type.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import unittest
|
|
9
|
+
|
|
10
|
+
from . import _bootstrap # noqa: F401
|
|
11
|
+
|
|
12
|
+
import resolve_invocation_target as rit # type: ignore
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# A valid-shape Salesforce Id is 15 or 18 alphanumeric chars. Prefixes below
|
|
16
|
+
# are chosen to avoid collision with _PREFIX_MAP so they exercise the
|
|
17
|
+
# "unknown prefix" path.
|
|
18
|
+
_APEX_ID_15 = "01p0000000ABC12"
|
|
19
|
+
_APEX_ID_18 = "01p0000000ABC12AAA"
|
|
20
|
+
_FLOW_DEF_ID_15 = "3000000000XYZ99"
|
|
21
|
+
_FLOW_VER_ID_15 = "3010000000XYZ99"
|
|
22
|
+
_PROMPT_ID_15 = "0hf0000000QRS77"
|
|
23
|
+
_UNKNOWN_PREFIX_ID_15 = "0aN000000000XYZ"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class KnownPrefixTests(unittest.TestCase):
|
|
27
|
+
def test_apex_prefix(self):
|
|
28
|
+
self.assertEqual(rit.resolve_target_id(_APEX_ID_15), ("apex", "tooling_soql"))
|
|
29
|
+
|
|
30
|
+
def test_flow_definition_prefix(self):
|
|
31
|
+
self.assertEqual(
|
|
32
|
+
rit.resolve_target_id(_FLOW_DEF_ID_15),
|
|
33
|
+
("flow_definition", "tooling_soql"),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def test_flow_version_prefix(self):
|
|
37
|
+
self.assertEqual(
|
|
38
|
+
rit.resolve_target_id(_FLOW_VER_ID_15),
|
|
39
|
+
("flow_version", "tooling_soql"),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def test_prompt_template_prefix(self):
|
|
43
|
+
self.assertEqual(
|
|
44
|
+
rit.resolve_target_id(_PROMPT_ID_15),
|
|
45
|
+
("prompt_template", "retrieve_required"),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def test_eighteen_char_id_works(self):
|
|
49
|
+
self.assertEqual(
|
|
50
|
+
rit.resolve_target_id(_APEX_ID_18),
|
|
51
|
+
("apex", "tooling_soql"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class UnknownPrefixTests(unittest.TestCase):
|
|
56
|
+
def test_resolve_target_id_never_raises(self):
|
|
57
|
+
# Unknown prefix → ("unknown", "skip"), no exception.
|
|
58
|
+
self.assertEqual(
|
|
59
|
+
rit.resolve_target_id(_UNKNOWN_PREFIX_ID_15),
|
|
60
|
+
("unknown", "skip"),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def test_resolve_or_unresolved_records_unknown_prefix(self):
|
|
64
|
+
unresolved: list[dict] = []
|
|
65
|
+
result = rit.resolve_or_unresolved(_UNKNOWN_PREFIX_ID_15, unresolved)
|
|
66
|
+
self.assertEqual(result, ("unknown", "skip"))
|
|
67
|
+
self.assertEqual(len(unresolved), 1)
|
|
68
|
+
entry = unresolved[0]
|
|
69
|
+
self.assertEqual(entry["id"], _UNKNOWN_PREFIX_ID_15)
|
|
70
|
+
self.assertEqual(entry["reason"], "unknown-id-prefix:0aN")
|
|
71
|
+
|
|
72
|
+
def test_known_prefix_does_not_touch_unresolved(self):
|
|
73
|
+
unresolved: list[dict] = []
|
|
74
|
+
result = rit.resolve_or_unresolved(_APEX_ID_15, unresolved)
|
|
75
|
+
self.assertEqual(result, ("apex", "tooling_soql"))
|
|
76
|
+
self.assertEqual(unresolved, [])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class InvalidShapeTests(unittest.TestCase):
|
|
80
|
+
def test_empty_string(self):
|
|
81
|
+
unresolved: list[dict] = []
|
|
82
|
+
result = rit.resolve_or_unresolved("", unresolved)
|
|
83
|
+
self.assertEqual(result, ("unknown", "skip"))
|
|
84
|
+
self.assertEqual(len(unresolved), 1)
|
|
85
|
+
self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
|
|
86
|
+
self.assertEqual(unresolved[0]["id"], "")
|
|
87
|
+
|
|
88
|
+
def test_none_coerced_via_str(self):
|
|
89
|
+
unresolved: list[dict] = []
|
|
90
|
+
result = rit.resolve_or_unresolved(None, unresolved)
|
|
91
|
+
self.assertEqual(result, ("unknown", "skip"))
|
|
92
|
+
self.assertEqual(len(unresolved), 1)
|
|
93
|
+
self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
|
|
94
|
+
self.assertEqual(unresolved[0]["id"], "None")
|
|
95
|
+
|
|
96
|
+
def test_wrong_length_is_invalid(self):
|
|
97
|
+
# A 10-char id-like string is not 15 or 18 — invalid shape, not
|
|
98
|
+
# an unknown prefix.
|
|
99
|
+
unresolved: list[dict] = []
|
|
100
|
+
rit.resolve_or_unresolved("01pABC1234", unresolved)
|
|
101
|
+
self.assertEqual(len(unresolved), 1)
|
|
102
|
+
self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
|
|
103
|
+
|
|
104
|
+
def test_bad_chars_rejected(self):
|
|
105
|
+
# 15-char length but contains punctuation — not an Id shape.
|
|
106
|
+
unresolved: list[dict] = []
|
|
107
|
+
rit.resolve_or_unresolved("01p!!!!!!!!!!99", unresolved)
|
|
108
|
+
self.assertEqual(len(unresolved), 1)
|
|
109
|
+
self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
|
|
110
|
+
|
|
111
|
+
def test_short_string_is_invalid(self):
|
|
112
|
+
unresolved: list[dict] = []
|
|
113
|
+
rit.resolve_or_unresolved("ab", unresolved)
|
|
114
|
+
self.assertEqual(len(unresolved), 1)
|
|
115
|
+
self.assertEqual(unresolved[0]["reason"], "invalid-id-format")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class RegisteredPrefixesTests(unittest.TestCase):
|
|
119
|
+
def test_exact_membership(self):
|
|
120
|
+
self.assertEqual(
|
|
121
|
+
rit.REGISTERED_PREFIXES,
|
|
122
|
+
frozenset({"01p", "300", "301", "0hf"}),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def test_is_frozenset(self):
|
|
126
|
+
"""Immutable so callers can't accidentally corrupt the table."""
|
|
127
|
+
self.assertIsInstance(rit.REGISTERED_PREFIXES, frozenset)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class ResolveTargetIdRobustnessTests(unittest.TestCase):
|
|
131
|
+
"""`resolve_target_id` is the lower-level helper — it must also never
|
|
132
|
+
raise, even on garbage input."""
|
|
133
|
+
|
|
134
|
+
def test_none_input(self):
|
|
135
|
+
self.assertEqual(rit.resolve_target_id(None), ("unknown", "skip")) # type: ignore[arg-type]
|
|
136
|
+
|
|
137
|
+
def test_empty_string(self):
|
|
138
|
+
self.assertEqual(rit.resolve_target_id(""), ("unknown", "skip"))
|
|
139
|
+
|
|
140
|
+
def test_too_short(self):
|
|
141
|
+
self.assertEqual(rit.resolve_target_id("ab"), ("unknown", "skip"))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
unittest.main()
|