@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,265 @@
|
|
|
1
|
+
"""Metadata API listMetadata wrappers — for sObjects that are NOT
|
|
2
|
+
exposed via SOQL on Tooling or Data API (e.g. GenAiPromptTemplate).
|
|
3
|
+
|
|
4
|
+
Wraps the sf CLI `sf org list metadata` recipe. Not a REST client call —
|
|
5
|
+
uses subprocess via sf_cli.run_sf. Failure semantics mirror the rest:
|
|
6
|
+
returns [] on known-missing + surfaces unresolved reasons upstream;
|
|
7
|
+
raises SfCliError / AuthRequired on unknown failures.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import subprocess
|
|
12
|
+
import xml.etree.ElementTree as ET
|
|
13
|
+
import zipfile
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Dict, List
|
|
16
|
+
|
|
17
|
+
from rest_client import redact_error
|
|
18
|
+
from sf_cli import (
|
|
19
|
+
AuthRequired,
|
|
20
|
+
_redact_subprocess_stderr,
|
|
21
|
+
_stderr_matches_auth,
|
|
22
|
+
run_sf,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Metadata XML default namespace — same as parse_bundle.NS. Duplicated
|
|
27
|
+
# (rather than imported) to keep the "no intra-skill imports" convention
|
|
28
|
+
# documented throughout the pipeline.
|
|
29
|
+
_NS = {"sf": "http://soap.sforce.com/2006/04/metadata"}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def list_prompt_template_metadata(org_alias: str) -> List[Dict[str, str]]:
|
|
33
|
+
"""Return every GenAiPromptTemplate metadata component in the org.
|
|
34
|
+
|
|
35
|
+
Each row has the shape produced by `sf org list metadata --json`:
|
|
36
|
+
{"id": "0hfUv...", "fullName": "AGNT_...", "type": "GenAiPromptTemplate",
|
|
37
|
+
"namespacePrefix": "...", ...}
|
|
38
|
+
|
|
39
|
+
Empty list on success with no templates. Raises SfCliError on CLI
|
|
40
|
+
failure (caller decides whether to treat as fatal).
|
|
41
|
+
"""
|
|
42
|
+
data = run_sf("list_metadata_genaiprompttemplate", ORG_ALIAS=org_alias)
|
|
43
|
+
result = data.get("result")
|
|
44
|
+
if not isinstance(result, list):
|
|
45
|
+
return []
|
|
46
|
+
return [r for r in result if isinstance(r, dict)]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _find_text(el: ET.Element | None, path: str) -> str | None:
|
|
50
|
+
if el is None:
|
|
51
|
+
return None
|
|
52
|
+
found = el.find(path, _NS)
|
|
53
|
+
if found is None:
|
|
54
|
+
return None
|
|
55
|
+
return found.text
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _parse_prompt_template_xml(xml_bytes: bytes) -> Dict[str, Any] | None:
|
|
59
|
+
"""Parse a single .genAiPromptTemplate XML file into a body dict.
|
|
60
|
+
|
|
61
|
+
Returns None on parse failure so the caller can log + skip. The
|
|
62
|
+
returned dict carries developerName/masterLabel/activeVersionIdentifier/
|
|
63
|
+
content/inputs — absent optional fields become None or empty lists.
|
|
64
|
+
|
|
65
|
+
Version selection: if multiple <templateVersions> elements exist,
|
|
66
|
+
prefer the one whose `versionIdentifier` matches the template-level
|
|
67
|
+
`activeVersionIdentifier`; otherwise fall back to the first version.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
root = ET.fromstring(xml_bytes)
|
|
71
|
+
except ET.ParseError:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
developer_name = _find_text(root, "sf:developerName")
|
|
75
|
+
master_label = _find_text(root, "sf:masterLabel")
|
|
76
|
+
active_version = _find_text(root, "sf:activeVersionIdentifier")
|
|
77
|
+
|
|
78
|
+
versions = root.findall("sf:templateVersions", _NS)
|
|
79
|
+
picked: ET.Element | None = None
|
|
80
|
+
if versions:
|
|
81
|
+
if active_version:
|
|
82
|
+
for v in versions:
|
|
83
|
+
vid = _find_text(v, "sf:versionIdentifier")
|
|
84
|
+
if vid and vid == active_version:
|
|
85
|
+
picked = v
|
|
86
|
+
break
|
|
87
|
+
if picked is None:
|
|
88
|
+
picked = versions[0]
|
|
89
|
+
|
|
90
|
+
content = _find_text(picked, "sf:content") if picked is not None else None
|
|
91
|
+
|
|
92
|
+
inputs: List[Dict[str, str]] = []
|
|
93
|
+
if picked is not None:
|
|
94
|
+
for inp in picked.findall("sf:inputs", _NS):
|
|
95
|
+
name = _find_text(inp, "sf:apiName") or _find_text(inp, "sf:name")
|
|
96
|
+
data_type = _find_text(inp, "sf:dataType")
|
|
97
|
+
if name is None and data_type is None:
|
|
98
|
+
continue
|
|
99
|
+
entry: Dict[str, str] = {}
|
|
100
|
+
if name is not None:
|
|
101
|
+
entry["name"] = name
|
|
102
|
+
if data_type is not None:
|
|
103
|
+
entry["dataType"] = data_type
|
|
104
|
+
inputs.append(entry)
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
"developerName": developer_name,
|
|
108
|
+
"masterLabel": master_label,
|
|
109
|
+
"activeVersionIdentifier": active_version,
|
|
110
|
+
"content": content,
|
|
111
|
+
"inputs": inputs,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# Timeout for `sf project retrieve start` — matches the prior YAML recipe's
|
|
116
|
+
# `timeout_seconds: 300`. Kept as a module constant (rather than a literal
|
|
117
|
+
# at the call site) so future adjustments have a single home.
|
|
118
|
+
_RETRIEVE_TIMEOUT_SECONDS = 300
|
|
119
|
+
|
|
120
|
+
# stderr patterns that mean "the CLI ran but there is no authenticated org
|
|
121
|
+
# for this alias" — reraised as AuthRequired. Mirrors the prior recipe's
|
|
122
|
+
# `auth_required_stderr_patterns` field.
|
|
123
|
+
_RETRIEVE_AUTH_PATTERNS = ("NoOrgAuthenticationError", "AuthInfoError")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _run_retrieve(argv: List[str], timeout: int) -> "subprocess.CompletedProcess[str]":
|
|
127
|
+
"""Thin wrapper over `subprocess.run` for the retrieve-start call.
|
|
128
|
+
|
|
129
|
+
Exists so tests can mock the subprocess boundary without also mocking
|
|
130
|
+
the argv-construction logic — see `RetrievePromptTemplatesTests`.
|
|
131
|
+
"""
|
|
132
|
+
return subprocess.run(
|
|
133
|
+
argv,
|
|
134
|
+
capture_output=True,
|
|
135
|
+
text=True,
|
|
136
|
+
timeout=timeout,
|
|
137
|
+
check=False,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def retrieve_prompt_templates(
|
|
142
|
+
org_alias: str,
|
|
143
|
+
template_names: List[str],
|
|
144
|
+
work_dir: Path,
|
|
145
|
+
) -> Dict[str, Dict[str, Any]]:
|
|
146
|
+
"""Retrieve GenAiPromptTemplate bodies via `sf project retrieve start`.
|
|
147
|
+
|
|
148
|
+
The sf plugin's `--metadata` flag is REPEATED once per requested
|
|
149
|
+
template (`--metadata GenAiPromptTemplate:A --metadata
|
|
150
|
+
GenAiPromptTemplate:B ...`). A comma-joined value is NOT a valid list;
|
|
151
|
+
the CLI treats the whole comma-joined string as a single malformed
|
|
152
|
+
member name, silently skips it, and the resulting zip contains only
|
|
153
|
+
`package.xml` (observed 2026-05-05 against my-org-alias). Hence we
|
|
154
|
+
bypass the YAML recipe loader here — `run_sf` substitutes
|
|
155
|
+
`{{METADATA_SPEC}}` single-shot and has no list-expansion primitive.
|
|
156
|
+
|
|
157
|
+
The resulting `unpackaged.zip` carries one `.genAiPromptTemplate` XML
|
|
158
|
+
file per template under `unpackaged/genAiPromptTemplates/`.
|
|
159
|
+
|
|
160
|
+
Returns a dict keyed by `developerName`. Templates the retrieve
|
|
161
|
+
didn't produce a file for are OMITTED (caller handles missing by
|
|
162
|
+
leaving them in `_pending_fetches`).
|
|
163
|
+
|
|
164
|
+
Failure modes:
|
|
165
|
+
- Empty `template_names` → short-circuits with `{}` and no sf call.
|
|
166
|
+
- `AuthRequired` (stderr matches auth patterns) → re-raised.
|
|
167
|
+
- `SfCliError` (any other non-zero exit, timeout, etc) → swallowed;
|
|
168
|
+
returns `{}`. Caller logs the retrieval-failure reason at the
|
|
169
|
+
call site.
|
|
170
|
+
- Zip missing or malformed → returns `{}`.
|
|
171
|
+
- XML parse failure on a specific file → that file is skipped; the
|
|
172
|
+
other templates in the same zip still parse and return.
|
|
173
|
+
"""
|
|
174
|
+
if not template_names:
|
|
175
|
+
return {}
|
|
176
|
+
|
|
177
|
+
retrieve_dir = work_dir / "prompt_template_retrieve"
|
|
178
|
+
retrieve_dir.mkdir(parents=True, exist_ok=True)
|
|
179
|
+
# Nuke stale files from a prior invocation so we don't trust an old
|
|
180
|
+
# unpackaged.zip if this run's sf call fails before writing one.
|
|
181
|
+
for path in retrieve_dir.iterdir():
|
|
182
|
+
if path.is_file():
|
|
183
|
+
path.unlink()
|
|
184
|
+
elif path.is_dir():
|
|
185
|
+
_rm_tree(path)
|
|
186
|
+
|
|
187
|
+
argv: List[str] = [
|
|
188
|
+
"sf",
|
|
189
|
+
"project",
|
|
190
|
+
"retrieve",
|
|
191
|
+
"start",
|
|
192
|
+
"--target-org",
|
|
193
|
+
org_alias,
|
|
194
|
+
"--target-metadata-dir",
|
|
195
|
+
str(retrieve_dir),
|
|
196
|
+
"--json",
|
|
197
|
+
]
|
|
198
|
+
for name in template_names:
|
|
199
|
+
argv.extend(["--metadata", f"GenAiPromptTemplate:{name}"])
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
cp = _run_retrieve(argv, _RETRIEVE_TIMEOUT_SECONDS)
|
|
203
|
+
except subprocess.TimeoutExpired as e:
|
|
204
|
+
# timeout exceptions may carry stderr; route through
|
|
205
|
+
# redact_error before surfacing — then swallow as non-fatal, same
|
|
206
|
+
# contract the old run_sf-based path had for SfCliError.
|
|
207
|
+
_ = redact_error(e)
|
|
208
|
+
return {}
|
|
209
|
+
except (OSError, subprocess.SubprocessError) as e:
|
|
210
|
+
_ = redact_error(e)
|
|
211
|
+
return {}
|
|
212
|
+
|
|
213
|
+
if cp.returncode != 0:
|
|
214
|
+
# Classify: auth failure re-raises, everything else is non-fatal.
|
|
215
|
+
if _stderr_matches_auth(cp.stderr, _RETRIEVE_AUTH_PATTERNS):
|
|
216
|
+
safe_stderr = _redact_subprocess_stderr(cp.stderr)
|
|
217
|
+
raise AuthRequired(safe_stderr or "auth required")
|
|
218
|
+
return {}
|
|
219
|
+
|
|
220
|
+
zip_path = retrieve_dir / "unpackaged.zip"
|
|
221
|
+
if not zip_path.exists():
|
|
222
|
+
return {}
|
|
223
|
+
|
|
224
|
+
results: Dict[str, Dict[str, Any]] = {}
|
|
225
|
+
try:
|
|
226
|
+
with zipfile.ZipFile(zip_path) as zf:
|
|
227
|
+
for info in zf.infolist():
|
|
228
|
+
name = info.filename
|
|
229
|
+
if not name.endswith(".genAiPromptTemplate"):
|
|
230
|
+
continue
|
|
231
|
+
if "genAiPromptTemplates/" not in name:
|
|
232
|
+
continue
|
|
233
|
+
try:
|
|
234
|
+
xml_bytes = zf.read(info)
|
|
235
|
+
except (KeyError, zipfile.BadZipFile):
|
|
236
|
+
continue
|
|
237
|
+
body = _parse_prompt_template_xml(xml_bytes)
|
|
238
|
+
if not body:
|
|
239
|
+
continue
|
|
240
|
+
dev_name = body.get("developerName")
|
|
241
|
+
if not dev_name:
|
|
242
|
+
# Fall back to the file stem if the XML somehow lacks
|
|
243
|
+
# a <developerName> element — keeps the caller's
|
|
244
|
+
# lookup working.
|
|
245
|
+
stem = Path(name).stem
|
|
246
|
+
if stem:
|
|
247
|
+
body["developerName"] = stem
|
|
248
|
+
dev_name = stem
|
|
249
|
+
if dev_name:
|
|
250
|
+
results[dev_name] = body
|
|
251
|
+
except zipfile.BadZipFile:
|
|
252
|
+
return {}
|
|
253
|
+
|
|
254
|
+
return results
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _rm_tree(path: Path) -> None:
|
|
258
|
+
"""Recursively delete a directory tree. stdlib-only, no shutil import
|
|
259
|
+
at module top to keep the import surface minimal."""
|
|
260
|
+
for child in path.iterdir():
|
|
261
|
+
if child.is_dir():
|
|
262
|
+
_rm_tree(child)
|
|
263
|
+
else:
|
|
264
|
+
child.unlink()
|
|
265
|
+
path.rmdir()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""ThreadPoolExecutor orchestrator for Wave B body fetches.
|
|
2
|
+
|
|
3
|
+
one failure MUST NOT abort the whole run. Callers merge failed kinds
|
|
4
|
+
into `_unresolved[]` with `reason=f'{kind}-fetch-failed:{redact_error(exc)}'`
|
|
5
|
+
and emit STATUS=PARTIAL_OK. We return a mixed list of (ok, result_or_exc)
|
|
6
|
+
tuples instead of raising on the first failure — which is what
|
|
7
|
+
`ThreadPoolExecutor.map` would do (and silently cancel remaining work in
|
|
8
|
+
the process).
|
|
9
|
+
|
|
10
|
+
Exception identity is preserved on the failure path: callers get the exact
|
|
11
|
+
exception object back so they can run it through `rest_client.redact_error`
|
|
12
|
+
at the point of logging. We intentionally do NOT stringify here — doing so
|
|
13
|
+
would lose structured info (urllib.error.HTTPError.code, etc.) and could
|
|
14
|
+
leak tokens into intermediate strings before redaction runs.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
19
|
+
from typing import Callable
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def fetch_bodies_parallel(
|
|
23
|
+
tasks: list[Callable[[], object]],
|
|
24
|
+
*,
|
|
25
|
+
max_workers: int = 5,
|
|
26
|
+
) -> list[tuple[bool, object]]:
|
|
27
|
+
"""Run zero-arg callables in parallel; return (ok, result_or_exc) per task.
|
|
28
|
+
|
|
29
|
+
contract:
|
|
30
|
+
* Each `task` is a zero-arg callable (use `functools.partial` to bind
|
|
31
|
+
args at the call site).
|
|
32
|
+
* On success, `(True, return_value)` is appended.
|
|
33
|
+
* On any exception, `(False, exc)` is appended — the EXC object itself,
|
|
34
|
+
not a stringification. Callers run it through `rest_client.redact_error`
|
|
35
|
+
before logging.
|
|
36
|
+
* Results are returned in INPUT ORDER, not completion order. Callers
|
|
37
|
+
frequently zip results back to their input tasks to identify which
|
|
38
|
+
target failed; completion order would break that contract.
|
|
39
|
+
* Empty task list returns `[]` without spinning up a pool.
|
|
40
|
+
* `max_workers=1` serializes — tasks run sequentially but the as_completed
|
|
41
|
+
path is still used (deterministic ordering preserved via index map).
|
|
42
|
+
* This function NEVER raises on a task failure. It may propagate
|
|
43
|
+
programmer errors (e.g., a non-callable in `tasks`) at submit time;
|
|
44
|
+
that's a bug surface, not a runtime failure mode.
|
|
45
|
+
"""
|
|
46
|
+
if not tasks:
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
# Pre-size the results list so we can assign by input index. This keeps
|
|
50
|
+
# output ordering deterministic and independent of completion timing,
|
|
51
|
+
# which matters for callers that identify failures positionally.
|
|
52
|
+
results: list[tuple[bool, object] | None] = [None] * len(tasks)
|
|
53
|
+
|
|
54
|
+
with ThreadPoolExecutor(max_workers=max_workers) as pool:
|
|
55
|
+
future_to_idx = {pool.submit(task): i for i, task in enumerate(tasks)}
|
|
56
|
+
for fut in as_completed(future_to_idx):
|
|
57
|
+
idx = future_to_idx[fut]
|
|
58
|
+
try:
|
|
59
|
+
results[idx] = (True, fut.result())
|
|
60
|
+
except Exception as exc: # noqa: BLE001 — see contract above
|
|
61
|
+
# Preserve exc identity; do NOT stringify here. Callers run
|
|
62
|
+
# this through rest_client.redact_error at log time .
|
|
63
|
+
# We catch Exception (not BaseException) so KeyboardInterrupt
|
|
64
|
+
# / SystemExit still propagate — those signal shutdown, not a
|
|
65
|
+
# task failure.
|
|
66
|
+
results[idx] = (False, exc)
|
|
67
|
+
|
|
68
|
+
# All slots filled by construction — futures/indexes are 1:1 with input.
|
|
69
|
+
return [r for r in results if r is not None] # type: ignore[return-value]
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Parse Bot.bot + GenAiPlannerBundle → _bundle_parsed.json + PLANNER_NAME.
|
|
3
|
+
|
|
4
|
+
Replaces old agent Phase 2a (Bot.bot planner-name extraction via XPath-ish
|
|
5
|
+
walk) + Phase 2c (bundle XML → topics/plannerActions + generation classifier).
|
|
6
|
+
|
|
7
|
+
Step 1 — planner name:
|
|
8
|
+
Read $WORK_DIR/sf_meta/wave1_bot/unpackaged/bots/*.bot XML.
|
|
9
|
+
Path: /Bot/botVersions[fullName==$AGENT_VERSION]/conversationDefinitionPlanners[0]
|
|
10
|
+
/genAiPlannerName (fallback: plannerName, fullName)
|
|
11
|
+
|
|
12
|
+
Step 2 — bundle (only if planner name resolved AND bundle dir exists):
|
|
13
|
+
Read $WORK_DIR/sf_meta/wave1_bundle/unpackaged/genAiPlannerBundles/<plannerName>/
|
|
14
|
+
*.genAiPlannerBundle
|
|
15
|
+
Extract: plannerType, description, masterLabel, localTopics[] with inline
|
|
16
|
+
localActions[], and (classic-only) plannerActions[].
|
|
17
|
+
Classify generation:
|
|
18
|
+
plannerType startswith "AiCopilot__" → classic
|
|
19
|
+
plannerType startswith "Atlas__" → nga
|
|
20
|
+
else → unknown
|
|
21
|
+
|
|
22
|
+
Emits:
|
|
23
|
+
$WORK_DIR/_bundle_parsed.json (full structured extraction)
|
|
24
|
+
$WORK_DIR/_agent_generation.txt (generation string, newline-terminated)
|
|
25
|
+
stdout: `PLANNER_NAME=<shlex-quoted>\nAGENT_GENERATION=<shlex-quoted>`
|
|
26
|
+
+ log lines (topic counts, action counts) for human readability.
|
|
27
|
+
|
|
28
|
+
If Bot.bot has no <conversationDefinitionPlanners>, prints `PLANNER_NAME=''`
|
|
29
|
+
and exits 0 — caller treats the tree as partial.
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
eval "$(python3 parse_bundle.py)"
|
|
33
|
+
|
|
34
|
+
Inputs (env):
|
|
35
|
+
WORK_DIR required
|
|
36
|
+
AGENT_VERSION required — used to pin the right <botVersions> element
|
|
37
|
+
|
|
38
|
+
Outputs:
|
|
39
|
+
files (above)
|
|
40
|
+
stdout eval-friendly K=V lines
|
|
41
|
+
exit 0 always (no recoverable error condition; missing XML → empty planner)
|
|
42
|
+
"""
|
|
43
|
+
import json
|
|
44
|
+
import os
|
|
45
|
+
import pathlib
|
|
46
|
+
import shlex
|
|
47
|
+
import sys
|
|
48
|
+
import xml.etree.ElementTree as ET
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
NS = {"sf": "http://soap.sforce.com/2006/04/metadata"}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _t(el, p):
|
|
55
|
+
if el is None:
|
|
56
|
+
return None
|
|
57
|
+
x = el.find(p, NS)
|
|
58
|
+
return x.text if x is not None else None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def classify_generation(planner_type: str) -> str:
|
|
62
|
+
if not planner_type:
|
|
63
|
+
return "unknown"
|
|
64
|
+
if planner_type.startswith("AiCopilot__"):
|
|
65
|
+
return "classic"
|
|
66
|
+
if planner_type.startswith("Atlas__"):
|
|
67
|
+
return "nga"
|
|
68
|
+
return "unknown"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def extract_planner_name(work_dir: pathlib.Path, target_ver: str) -> str:
|
|
72
|
+
bots_dir = work_dir / "sf_meta" / "wave1_bot" / "unpackaged" / "bots"
|
|
73
|
+
if not bots_dir.exists():
|
|
74
|
+
return ""
|
|
75
|
+
for bot_file in bots_dir.glob("*.bot"):
|
|
76
|
+
try:
|
|
77
|
+
root = ET.parse(bot_file).getroot()
|
|
78
|
+
except ET.ParseError:
|
|
79
|
+
continue
|
|
80
|
+
for bv in root.findall("sf:botVersions", NS):
|
|
81
|
+
full = _t(bv, "sf:fullName") or _t(bv, "sf:developerName")
|
|
82
|
+
if target_ver and full != target_ver:
|
|
83
|
+
continue
|
|
84
|
+
for cdp in bv.findall("sf:conversationDefinitionPlanners", NS):
|
|
85
|
+
n = (_t(cdp, "sf:genAiPlannerName")
|
|
86
|
+
or _t(cdp, "sf:plannerName")
|
|
87
|
+
or _t(cdp, "sf:fullName"))
|
|
88
|
+
if n:
|
|
89
|
+
return n
|
|
90
|
+
return ""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def extract_bundle(work_dir: pathlib.Path, planner_name: str) -> dict:
|
|
94
|
+
bundle = {
|
|
95
|
+
"plannerType": None,
|
|
96
|
+
"plannerName": planner_name or None,
|
|
97
|
+
"generation": "unknown",
|
|
98
|
+
"description": None,
|
|
99
|
+
"masterLabel": None,
|
|
100
|
+
"topics": [],
|
|
101
|
+
"plannerActions": [],
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
planner_root = work_dir / "sf_meta" / "wave1_bundle" / "unpackaged" / "genAiPlannerBundles"
|
|
105
|
+
if not planner_root.exists():
|
|
106
|
+
return bundle
|
|
107
|
+
|
|
108
|
+
for bundle_dir in planner_root.iterdir():
|
|
109
|
+
if not bundle_dir.is_dir():
|
|
110
|
+
continue
|
|
111
|
+
bundle_xml = list(bundle_dir.glob("*.genAiPlannerBundle"))
|
|
112
|
+
if not bundle_xml:
|
|
113
|
+
continue
|
|
114
|
+
try:
|
|
115
|
+
root = ET.parse(bundle_xml[0]).getroot()
|
|
116
|
+
except ET.ParseError as e:
|
|
117
|
+
sys.stderr.write(f"parse_bundle.py: XML parse error on {bundle_xml[0]}: {e}\n")
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
bundle["plannerType"] = _t(root, "sf:plannerType")
|
|
121
|
+
bundle["generation"] = classify_generation(bundle["plannerType"])
|
|
122
|
+
bundle["description"] = _t(root, "sf:description")
|
|
123
|
+
bundle["masterLabel"] = _t(root, "sf:masterLabel")
|
|
124
|
+
|
|
125
|
+
for lt in root.findall("sf:localTopics", NS):
|
|
126
|
+
tname = _t(lt, "sf:developerName") or _t(lt, "sf:fullName")
|
|
127
|
+
if not tname:
|
|
128
|
+
continue
|
|
129
|
+
topic = {
|
|
130
|
+
"name": tname,
|
|
131
|
+
"localDeveloperName": _t(lt, "sf:localDeveloperName"),
|
|
132
|
+
"masterLabel": _t(lt, "sf:masterLabel"),
|
|
133
|
+
"description": _t(lt, "sf:description"),
|
|
134
|
+
"canEscalate": (_t(lt, "sf:canEscalate") or "false").lower() == "true",
|
|
135
|
+
"pluginType": _t(lt, "sf:pluginType"),
|
|
136
|
+
"actions": [],
|
|
137
|
+
}
|
|
138
|
+
for la in lt.findall("sf:localActions", NS):
|
|
139
|
+
aname = _t(la, "sf:developerName") or _t(la, "sf:fullName")
|
|
140
|
+
if not aname:
|
|
141
|
+
continue
|
|
142
|
+
topic["actions"].append({
|
|
143
|
+
"name": aname,
|
|
144
|
+
"localDeveloperName": _t(la, "sf:localDeveloperName"),
|
|
145
|
+
"masterLabel": _t(la, "sf:masterLabel"),
|
|
146
|
+
"description": _t(la, "sf:description"),
|
|
147
|
+
"invocationTarget": _t(la, "sf:invocationTarget"),
|
|
148
|
+
"invocationTargetType": (_t(la, "sf:invocationTargetType") or "").strip(),
|
|
149
|
+
"source": _t(la, "sf:source"),
|
|
150
|
+
})
|
|
151
|
+
bundle["topics"].append(topic)
|
|
152
|
+
|
|
153
|
+
for pa in root.findall("sf:plannerActions", NS):
|
|
154
|
+
aname = _t(pa, "sf:developerName") or _t(pa, "sf:fullName")
|
|
155
|
+
if not aname:
|
|
156
|
+
continue
|
|
157
|
+
bundle["plannerActions"].append({
|
|
158
|
+
"name": aname,
|
|
159
|
+
"localDeveloperName": _t(pa, "sf:localDeveloperName"),
|
|
160
|
+
"masterLabel": _t(pa, "sf:masterLabel"),
|
|
161
|
+
"description": _t(pa, "sf:description"),
|
|
162
|
+
"invocationTarget": _t(pa, "sf:invocationTarget"),
|
|
163
|
+
"invocationTargetType": (_t(pa, "sf:invocationTargetType") or "").strip(),
|
|
164
|
+
"source": _t(pa, "sf:source"),
|
|
165
|
+
})
|
|
166
|
+
break # first bundle dir is enough
|
|
167
|
+
return bundle
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def atomic_write(path: pathlib.Path, content: str) -> None:
|
|
171
|
+
tmp = path.with_suffix(path.suffix + ".tmp")
|
|
172
|
+
tmp.write_text(content)
|
|
173
|
+
os.replace(tmp, path)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def main() -> int:
|
|
177
|
+
try:
|
|
178
|
+
work_dir = pathlib.Path(os.environ["WORK_DIR"])
|
|
179
|
+
agent_version = os.environ["AGENT_VERSION"]
|
|
180
|
+
except KeyError as e:
|
|
181
|
+
sys.stderr.write(f"parse_bundle.py: missing env {e}\n")
|
|
182
|
+
return 1
|
|
183
|
+
|
|
184
|
+
# Step 1: planner name
|
|
185
|
+
planner_name = extract_planner_name(work_dir, agent_version)
|
|
186
|
+
|
|
187
|
+
# Step 2: bundle (only if planner resolved)
|
|
188
|
+
bundle = extract_bundle(work_dir, planner_name) if planner_name else {
|
|
189
|
+
"plannerType": None, "plannerName": None, "generation": "unknown",
|
|
190
|
+
"description": None, "masterLabel": None, "topics": [], "plannerActions": [],
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
atomic_write(work_dir / "_bundle_parsed.json", json.dumps(bundle, indent=2))
|
|
194
|
+
atomic_write(work_dir / "_agent_generation.txt", bundle["generation"] + "\n")
|
|
195
|
+
|
|
196
|
+
# Log lines (stderr would be lost via eval; use stderr for logs not shell-consumed)
|
|
197
|
+
total_actions = (
|
|
198
|
+
sum(len(t["actions"]) for t in bundle["topics"]) + len(bundle["plannerActions"])
|
|
199
|
+
)
|
|
200
|
+
sys.stderr.write(
|
|
201
|
+
f"[parse_bundle] plannerName={planner_name!r} "
|
|
202
|
+
f"plannerType={bundle['plannerType']!r} generation={bundle['generation']}\n"
|
|
203
|
+
f"[parse_bundle] topics={len(bundle['topics'])} "
|
|
204
|
+
f"topic-scope-actions={sum(len(t['actions']) for t in bundle['topics'])} "
|
|
205
|
+
f"bundle-scope-actions={len(bundle['plannerActions'])} total={total_actions}\n"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Eval-friendly stdout
|
|
209
|
+
sys.stdout.write(f"PLANNER_NAME={shlex.quote(planner_name)}\n")
|
|
210
|
+
sys.stdout.write(f"AGENT_GENERATION={shlex.quote(bundle['generation'])}\n")
|
|
211
|
+
return 0
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if __name__ == "__main__":
|
|
215
|
+
sys.exit(main())
|