@salesforce/afv-skills 1.21.0 → 1.22.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/agentforce-architecture-analyze/README.md +156 -0
- package/skills/agentforce-architecture-analyze/SKILL.md +230 -0
- package/skills/agentforce-architecture-analyze/assets/cli/describe_sobject.yaml +16 -0
- package/skills/agentforce-architecture-analyze/assets/cli/describe_tooling_sobject.yaml +17 -0
- package/skills/agentforce-architecture-analyze/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
- package/skills/agentforce-architecture-analyze/assets/cli/org_display.yaml +15 -0
- package/skills/agentforce-architecture-analyze/assets/cli/retrieve_genai_plugin.yaml +18 -0
- package/skills/agentforce-architecture-analyze/assets/cli/show_access_token.yaml +27 -0
- package/skills/agentforce-architecture-analyze/assets/mermaid/action_tree.mmd +20 -0
- package/skills/agentforce-architecture-analyze/assets/mermaid/data_flow.mmd +19 -0
- package/skills/agentforce-architecture-analyze/assets/mermaid/dependency_graph.mmd +19 -0
- package/skills/agentforce-architecture-analyze/assets/mermaid/invocation_sequence.mmd +20 -0
- package/skills/agentforce-architecture-analyze/assets/mermaid/planner_state.mmd +18 -0
- package/skills/agentforce-architecture-analyze/assets/soql/apex_class_bodies_by_ids.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/apex_class_bodies_by_names.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/bot_definition_details.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/bot_version_lookup.soql +4 -0
- package/skills/agentforce-architecture-analyze/assets/soql/flow_definition_by_ids.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/flow_definition_ids_by_names.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
- package/skills/agentforce-architecture-analyze/assets/soql/flow_metadata_by_id.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/functions_by_plugins.soql +5 -0
- package/skills/agentforce-architecture-analyze/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/planner_bundle_functions.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/planner_definition_by_agent_chain.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
- package/skills/agentforce-architecture-analyze/assets/soql/plugins_by_planner.soql +4 -0
- package/skills/agentforce-architecture-analyze/references/architecture_sections.md +243 -0
- package/skills/agentforce-architecture-analyze/references/contract.json +244 -0
- package/skills/agentforce-architecture-analyze/references/soql_fields.md +512 -0
- package/skills/agentforce-architecture-analyze/scripts/_shared/__init__.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/_shared/fs_guard.py +329 -0
- package/skills/agentforce-architecture-analyze/scripts/_shared/paths.py +110 -0
- package/skills/agentforce-architecture-analyze/scripts/_shared/runtime.py +59 -0
- package/skills/agentforce-architecture-analyze/scripts/_shared/sql.py +10 -0
- package/skills/agentforce-architecture-analyze/scripts/cache_check.py +234 -0
- package/skills/agentforce-architecture-analyze/scripts/config.py +131 -0
- package/skills/agentforce-architecture-analyze/scripts/fetch_soql.py +689 -0
- package/skills/agentforce-architecture-analyze/scripts/finalize.py +295 -0
- package/skills/agentforce-architecture-analyze/scripts/main.py +2835 -0
- package/skills/agentforce-architecture-analyze/scripts/metadata_listing.py +265 -0
- package/skills/agentforce-architecture-analyze/scripts/parallel_retrieve.py +69 -0
- package/skills/agentforce-architecture-analyze/scripts/parse_bundle.py +215 -0
- package/skills/agentforce-architecture-analyze/scripts/parse_wave.py +845 -0
- package/skills/agentforce-architecture-analyze/scripts/probe_channels.py +302 -0
- package/skills/agentforce-architecture-analyze/scripts/render_architecture.py +1043 -0
- package/skills/agentforce-architecture-analyze/scripts/resolve_bot.py +255 -0
- package/skills/agentforce-architecture-analyze/scripts/resolve_invocation_target.py +130 -0
- package/skills/agentforce-architecture-analyze/scripts/rest_client.py +763 -0
- package/skills/agentforce-architecture-analyze/scripts/retrieve_planner.py +13 -0
- package/skills/agentforce-architecture-analyze/scripts/sf_cli.py +242 -0
- package/skills/agentforce-architecture-analyze/scripts/soql_loader.py +253 -0
- package/skills/agentforce-architecture-analyze/scripts/summarize_tree.py +143 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/__init__.py +0 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/_bootstrap.py +23 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/fixtures/genai_payloads.py +400 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_cache_check.py +307 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_cache_check_main.py +283 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_config.py +115 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_end_to_end_fixture.py +651 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_finalize.py +278 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_flow_children_inflation.py +582 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_fs_guard.py +113 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_iterative_wave_b.py +478 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_main_pipeline.py +3359 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parallel_retrieve.py +131 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parse_bundle.py +400 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parse_wave.py +644 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parse_wave_classifiers.py +224 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parse_wave_helpers.py +380 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_parse_wave_main.py +397 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_per_branch_visited.py +244 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_probe_channels.py +359 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_probe_cli_recipes.py +185 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_render_architecture.py +810 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_bot.py +203 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_creds.py +157 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_invocation_target.py +145 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_rest_client.py +1253 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_runtime_override.py +100 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_sf_cli.py +261 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_signature_stamping.py +466 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_soql_loader.py +501 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_summarize_tree.py +241 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_write_emit_ctx.py +480 -0
- package/skills/agentforce-architecture-analyze/tools/emit_env.py +157 -0
- package/skills/agentforce-architecture-analyze/tools/emit_result.py +262 -0
- package/skills/agentforce-architecture-analyze/tools/sanitize.py +33 -0
- package/skills/agentforce-architecture-analyze/tools/write_emit_ctx.py +332 -0
- package/skills/agentforce-d360-analyze/README.md +123 -0
- package/skills/agentforce-d360-analyze/SKILL.md +163 -0
- package/skills/agentforce-d360-analyze/assets/dc/app_generation.sql +51 -0
- package/skills/agentforce-d360-analyze/assets/dc/content_category.sql +44 -0
- package/skills/agentforce-d360-analyze/assets/dc/content_quality.sql +41 -0
- package/skills/agentforce-d360-analyze/assets/dc/discover_sessions.sql +36 -0
- package/skills/agentforce-d360-analyze/assets/dc/feedback.sql +47 -0
- package/skills/agentforce-d360-analyze/assets/dc/feedback_details.sql +38 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_records.sql +45 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_request_llm.sql +50 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_request_metadata.sql +44 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_request_tags.sql +42 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_requests.sql +89 -0
- package/skills/agentforce-d360-analyze/assets/dc/gateway_responses.sql +43 -0
- package/skills/agentforce-d360-analyze/assets/dc/generations.sql +52 -0
- package/skills/agentforce-d360-analyze/assets/dc/interactions.sql +53 -0
- package/skills/agentforce-d360-analyze/assets/dc/messages.sql +53 -0
- package/skills/agentforce-d360-analyze/assets/dc/messaging_session.sql +37 -0
- package/skills/agentforce-d360-analyze/assets/dc/moment_interactions.sql +34 -0
- package/skills/agentforce-d360-analyze/assets/dc/moments.sql +39 -0
- package/skills/agentforce-d360-analyze/assets/dc/participants.sql +48 -0
- package/skills/agentforce-d360-analyze/assets/dc/sessions.sql +78 -0
- package/skills/agentforce-d360-analyze/assets/dc/steps.sql +64 -0
- package/skills/agentforce-d360-analyze/assets/dc/tag_associations.sql +46 -0
- package/skills/agentforce-d360-analyze/assets/dc/tag_definition_associations.sql +37 -0
- package/skills/agentforce-d360-analyze/assets/dc/tag_definitions.sql +50 -0
- package/skills/agentforce-d360-analyze/assets/dc/tags.sql +37 -0
- package/skills/agentforce-d360-analyze/assets/dc/telemetry_spans.sql +55 -0
- package/skills/agentforce-d360-analyze/references/artifacts.md +50 -0
- package/skills/agentforce-d360-analyze/references/dc_dmo_fields.md +823 -0
- package/skills/agentforce-d360-analyze/references/dc_pipeline_contract.md +608 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/__init__.py +2 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/cli_override.py +98 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/fs_guard.py +334 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/paths.py +155 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/runtime.py +59 -0
- package/skills/agentforce-d360-analyze/scripts/_shared/sql.py +14 -0
- package/skills/agentforce-d360-analyze/scripts/assemble_dc.py +1624 -0
- package/skills/agentforce-d360-analyze/scripts/config.py +45 -0
- package/skills/agentforce-d360-analyze/scripts/dc.py +188 -0
- package/skills/agentforce-d360-analyze/scripts/discover_sessions.py +556 -0
- package/skills/agentforce-d360-analyze/scripts/fetch_dc.py +1045 -0
- package/skills/agentforce-d360-analyze/scripts/render_dc.py +1750 -0
- package/skills/agentforce-d360-analyze/scripts/resolve_session.py +264 -0
- package/skills/agentforce-d360-analyze/scripts/storage.py +92 -0
- package/skills/agentforce-d360-analyze/scripts/tests/__init__.py +0 -0
- package/skills/agentforce-d360-analyze/scripts/tests/_bootstrap.py +15 -0
- package/skills/agentforce-d360-analyze/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/agentforce-d360-analyze/scripts/tests/fixtures/synthetic_session.py +424 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_assemble_dc_helpers.py +287 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_assemble_dc_integration.py +247 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_dc_and_resolve_session.py +433 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions.py +458 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_fetch_dc_helpers.py +266 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_fetch_dc_identity.py +528 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_fetch_dc_main.py +251 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_fetch_dc_waterfall.py +229 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_identity_coherence.py +327 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_branches.py +256 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_gateway_direct.py +130 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_helpers.py +291 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_integration.py +220 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_from_disk.py +100 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_session_main.py +149 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_runtime_override.py +104 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_session_shape.py +95 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
- package/skills/agentforce-generate/README.md +112 -0
- package/skills/agentforce-generate/SKILL.md +518 -0
- package/skills/agentforce-generate/assets/README-legacy.md +89 -0
- package/skills/agentforce-generate/assets/agent-spec-template.md +90 -0
- package/skills/agentforce-generate/assets/agents/README.md +45 -0
- package/skills/agentforce-generate/assets/agents/hello-world.agent +60 -0
- package/skills/agentforce-generate/assets/agents/multi-subagent.agent +105 -0
- package/skills/agentforce-generate/assets/agents/order-service.agent +272 -0
- package/skills/agentforce-generate/assets/agents/production-faq.agent +101 -0
- package/skills/agentforce-generate/assets/agents/production-faq.bundle-meta.xml +4 -0
- package/skills/agentforce-generate/assets/agents/simple-qa.agent +72 -0
- package/skills/agentforce-generate/assets/agents/verification-gate.agent +280 -0
- package/skills/agentforce-generate/assets/apex/models-api-queueable.cls +225 -0
- package/skills/agentforce-generate/assets/bundle-meta.xml +23 -0
- package/skills/agentforce-generate/assets/components/apex-action.agent +52 -0
- package/skills/agentforce-generate/assets/components/error-handling.agent +58 -0
- package/skills/agentforce-generate/assets/components/escalation-setup.agent +169 -0
- package/skills/agentforce-generate/assets/components/flow-action.agent +66 -0
- package/skills/agentforce-generate/assets/components/n-ary-conditions.agent +110 -0
- package/skills/agentforce-generate/assets/components/subagent-with-actions.agent +40 -0
- package/skills/agentforce-generate/assets/deterministic-routing.agent +166 -0
- package/skills/agentforce-generate/assets/escalation-pattern.agent +209 -0
- package/skills/agentforce-generate/assets/flow-action-lookup.agent +115 -0
- package/skills/agentforce-generate/assets/hub-and-spoke.agent +104 -0
- package/skills/agentforce-generate/assets/invocable-apex-template.cls +187 -0
- package/skills/agentforce-generate/assets/local-info-agent-annotated.agent +355 -0
- package/skills/agentforce-generate/assets/metadata/basic-prompt-template.promptTemplate-meta.xml +109 -0
- package/skills/agentforce-generate/assets/metadata/genai-function-apex.xml +92 -0
- package/skills/agentforce-generate/assets/metadata/genai-function-flow.xml +57 -0
- package/skills/agentforce-generate/assets/metadata/genai-plugin.xml +72 -0
- package/skills/agentforce-generate/assets/metadata/http-callout-flow.flow-meta.xml +348 -0
- package/skills/agentforce-generate/assets/metadata/record-grounded-prompt.promptTemplate-meta.xml +136 -0
- package/skills/agentforce-generate/assets/minimal-starter.agent +42 -0
- package/skills/agentforce-generate/assets/patterns/README.md +254 -0
- package/skills/agentforce-generate/assets/patterns/action-callbacks.agent +178 -0
- package/skills/agentforce-generate/assets/patterns/advanced-input-bindings.agent +141 -0
- package/skills/agentforce-generate/assets/patterns/bidirectional-routing.agent +156 -0
- package/skills/agentforce-generate/assets/patterns/critical-input-collection.agent +244 -0
- package/skills/agentforce-generate/assets/patterns/delegation-routing.agent +89 -0
- package/skills/agentforce-generate/assets/patterns/lifecycle-events.agent +127 -0
- package/skills/agentforce-generate/assets/patterns/llm-controlled-actions.agent +184 -0
- package/skills/agentforce-generate/assets/patterns/multi-step-workflow.agent +282 -0
- package/skills/agentforce-generate/assets/patterns/open-gate-routing.agent +287 -0
- package/skills/agentforce-generate/assets/patterns/procedural-instructions.agent +273 -0
- package/skills/agentforce-generate/assets/patterns/prompt-template-action.agent +188 -0
- package/skills/agentforce-generate/assets/patterns/system-instruction-overrides.agent +293 -0
- package/skills/agentforce-generate/assets/prompt-rag-search.agent +131 -0
- package/skills/agentforce-generate/assets/template-multi-subagent.agent +160 -0
- package/skills/agentforce-generate/assets/template-single-subagent.agent +81 -0
- package/skills/agentforce-generate/assets/verification-gate.agent +208 -0
- package/skills/agentforce-generate/references/action-prompt-templates.md +164 -0
- package/skills/agentforce-generate/references/actions-reference.md +612 -0
- package/skills/agentforce-generate/references/agent-access-guide.md +72 -0
- package/skills/agentforce-generate/references/agent-design-and-spec-creation.md +1010 -0
- package/skills/agentforce-generate/references/agent-metadata-and-lifecycle.md +575 -0
- package/skills/agentforce-generate/references/agent-script-core-language.md +1255 -0
- package/skills/agentforce-generate/references/agent-subagent-map-diagrams.md +323 -0
- package/skills/agentforce-generate/references/agent-user-setup.md +529 -0
- package/skills/agentforce-generate/references/agent-validation-and-debugging.md +805 -0
- package/skills/agentforce-generate/references/architecture-patterns.md +158 -0
- package/skills/agentforce-generate/references/complex-data-types.md +57 -0
- package/skills/agentforce-generate/references/deploy-reference.md +134 -0
- package/skills/agentforce-generate/references/discover-reference.md +102 -0
- package/skills/agentforce-generate/references/examples.md +350 -0
- package/skills/agentforce-generate/references/feature-validity.md +43 -0
- package/skills/agentforce-generate/references/instruction-resolution.md +545 -0
- package/skills/agentforce-generate/references/known-issues.md +353 -0
- package/skills/agentforce-generate/references/minimal-examples.md +67 -0
- package/skills/agentforce-generate/references/production-gotchas.md +300 -0
- package/skills/agentforce-generate/references/safety-review-reference.md +145 -0
- package/skills/agentforce-generate/references/salesforce-cli-for-agents.md +395 -0
- package/skills/agentforce-generate/references/scaffold-reference.md +153 -0
- package/skills/agentforce-generate/references/scoring-rubric.md +24 -0
- package/skills/agentforce-generate/references/version-history.md +23 -0
- package/skills/agentforce-observe/SKILL.md +366 -0
- package/skills/agentforce-observe/apex/AgentforceOptimizeService.cls +1262 -0
- package/skills/agentforce-observe/apex/AgentforceOptimizeService.cls-meta.xml +5 -0
- package/skills/agentforce-observe/references/improve-reference.md +359 -0
- package/skills/agentforce-observe/references/issue-classification.md +220 -0
- package/skills/agentforce-observe/references/reproduce-reference.md +131 -0
- package/skills/agentforce-observe/references/stdm-queries.md +373 -0
- package/skills/agentforce-observe/references/stdm-schema.md +189 -0
- package/skills/agentforce-test/SKILL.md +333 -0
- package/skills/agentforce-test/assets/basic-test-spec.yaml +63 -0
- package/skills/agentforce-test/assets/guardrail-test-spec.yaml +105 -0
- package/skills/agentforce-test/assets/standard-test-spec.yaml +127 -0
- package/skills/agentforce-test/references/action-execution.md +241 -0
- package/skills/agentforce-test/references/batch-testing.md +274 -0
- package/skills/agentforce-test/references/preview-testing.md +353 -0
- package/skills/agentforce-test/references/test-report-format.md +160 -0
- package/skills/agentforce-test/references/troubleshooting.md +73 -0
- package/skills/analyzing-test-failures/SKILL.md +1 -1
- package/skills/automation-flow-generate/SKILL.md +372 -0
- package/skills/commerce-b2b-open-code-components-integrate/SKILL.md +165 -0
- package/skills/commerce-b2b-store-create/SKILL.md +167 -0
- package/skills/commerce-b2b-store-create/references/store-vs-storefront.md +169 -0
- package/skills/creating-fix-work-item/SKILL.md +1 -1
- package/skills/data360-activate/CREDITS.md +5 -0
- package/skills/data360-activate/README.md +39 -0
- package/skills/data360-activate/SKILL.md +117 -0
- package/skills/data360-connect/CREDITS.md +5 -0
- package/skills/data360-connect/README.md +59 -0
- package/skills/data360-connect/SKILL.md +154 -0
- package/skills/data360-connect/examples/connections/heroku-postgres.json +15 -0
- package/skills/data360-connect/examples/connections/ingest-api-connection.json +5 -0
- package/skills/data360-connect/examples/connections/ingest-api-schema.json +31 -0
- package/skills/data360-connect/examples/connections/redshift.json +16 -0
- package/skills/data360-connect/examples/connections/sharepoint-unstructured.json +20 -0
- package/skills/data360-connect/examples/connections/snowflake-connection.json +42 -0
- package/skills/data360-harmonize/CREDITS.md +3 -0
- package/skills/data360-harmonize/README.md +31 -0
- package/skills/data360-harmonize/SKILL.md +116 -0
- package/skills/data360-orchestrate/CREDITS.md +15 -0
- package/skills/data360-orchestrate/README.md +127 -0
- package/skills/data360-orchestrate/SKILL.md +235 -0
- package/skills/data360-orchestrate/UPSTREAM.md +45 -0
- package/skills/data360-orchestrate/assets/definitions/activation-target.template.json +5 -0
- package/skills/data360-orchestrate/assets/definitions/activation.template.json +7 -0
- package/skills/data360-orchestrate/assets/definitions/calculated-insight.template.json +7 -0
- package/skills/data360-orchestrate/assets/definitions/data-action-target.template.json +5 -0
- package/skills/data360-orchestrate/assets/definitions/data-action.template.json +5 -0
- package/skills/data360-orchestrate/assets/definitions/data-graph.template.json +21 -0
- package/skills/data360-orchestrate/assets/definitions/data-stream.template.json +55 -0
- package/skills/data360-orchestrate/assets/definitions/dmo.template.json +17 -0
- package/skills/data360-orchestrate/assets/definitions/identity-resolution.template.json +30 -0
- package/skills/data360-orchestrate/assets/definitions/mapping.template.json +14 -0
- package/skills/data360-orchestrate/assets/definitions/relationship.template.json +12 -0
- package/skills/data360-orchestrate/assets/definitions/search-index.template.json +9 -0
- package/skills/data360-orchestrate/assets/definitions/segment.template.json +16 -0
- package/skills/data360-orchestrate/references/feature-readiness.md +157 -0
- package/skills/data360-orchestrate/references/plugin-setup.md +138 -0
- package/skills/data360-orchestrate/scripts/bootstrap-plugin.sh +53 -0
- package/skills/data360-orchestrate/scripts/diagnose-org.mjs +511 -0
- package/skills/data360-orchestrate/scripts/generate-manifest.mjs +68 -0
- package/skills/data360-orchestrate/scripts/verify-plugin.sh +58 -0
- package/skills/data360-prepare/CREDITS.md +7 -0
- package/skills/data360-prepare/README.md +51 -0
- package/skills/data360-prepare/SKILL.md +190 -0
- package/skills/data360-prepare/examples/ingestion-api/.env.example +8 -0
- package/skills/data360-prepare/examples/ingestion-api/README.md +48 -0
- package/skills/data360-prepare/examples/ingestion-api/send-data.py +144 -0
- package/skills/data360-query/CREDITS.md +7 -0
- package/skills/data360-query/README.md +44 -0
- package/skills/data360-query/SKILL.md +119 -0
- package/skills/data360-query/examples/search-indexes/hybrid-structured.json +44 -0
- package/skills/data360-query/examples/search-indexes/vector-knowledge.json +43 -0
- package/skills/data360-segment/CREDITS.md +3 -0
- package/skills/data360-segment/README.md +36 -0
- package/skills/data360-segment/SKILL.md +114 -0
- package/skills/design-systems-slds-apply/SKILL.md +322 -0
- package/skills/design-systems-slds-apply/checklists.md +83 -0
- package/skills/design-systems-slds-apply/examples.md +283 -0
- package/skills/design-systems-slds-apply/guidance/README.md +83 -0
- package/skills/design-systems-slds-apply/guidance/blueprints-index.md +213 -0
- package/skills/design-systems-slds-apply/guidance/icons-guidance.md +186 -0
- package/skills/design-systems-slds-apply/guidance/overviews/borders.md +236 -0
- package/skills/design-systems-slds-apply/guidance/overviews/color.md +266 -0
- package/skills/design-systems-slds-apply/guidance/overviews/display-density.md +366 -0
- package/skills/design-systems-slds-apply/guidance/overviews/icons.md +240 -0
- package/skills/design-systems-slds-apply/guidance/overviews/illustrations.md +235 -0
- package/skills/design-systems-slds-apply/guidance/overviews/shadows.md +176 -0
- package/skills/design-systems-slds-apply/guidance/overviews/spacing.md +216 -0
- package/skills/design-systems-slds-apply/guidance/overviews/typography.md +323 -0
- package/skills/design-systems-slds-apply/guidance/overviews/utilities.md +542 -0
- package/skills/design-systems-slds-apply/guidance/slds-development-guide.md +288 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/borders.md +202 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/index.md +171 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/color/system-hooks.md +132 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/index.md +327 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/shadows.md +238 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/spacing.md +254 -0
- package/skills/design-systems-slds-apply/guidance/styling-hooks/typography.md +448 -0
- package/skills/design-systems-slds-apply/guidance/utilities/alignment.md +119 -0
- package/skills/design-systems-slds-apply/guidance/utilities/borders.md +131 -0
- package/skills/design-systems-slds-apply/guidance/utilities/box.md +125 -0
- package/skills/design-systems-slds-apply/guidance/utilities/color.md +165 -0
- package/skills/design-systems-slds-apply/guidance/utilities/dark-mode.md +111 -0
- package/skills/design-systems-slds-apply/guidance/utilities/description-list.md +168 -0
- package/skills/design-systems-slds-apply/guidance/utilities/floats.md +117 -0
- package/skills/design-systems-slds-apply/guidance/utilities/grid.md +264 -0
- package/skills/design-systems-slds-apply/guidance/utilities/horizontal-list.md +110 -0
- package/skills/design-systems-slds-apply/guidance/utilities/hyphenation.md +84 -0
- package/skills/design-systems-slds-apply/guidance/utilities/index.md +205 -0
- package/skills/design-systems-slds-apply/guidance/utilities/interactions.md +89 -0
- package/skills/design-systems-slds-apply/guidance/utilities/layout.md +109 -0
- package/skills/design-systems-slds-apply/guidance/utilities/line-clamp.md +131 -0
- package/skills/design-systems-slds-apply/guidance/utilities/margin.md +155 -0
- package/skills/design-systems-slds-apply/guidance/utilities/media-object.md +161 -0
- package/skills/design-systems-slds-apply/guidance/utilities/name-value-list.md +152 -0
- package/skills/design-systems-slds-apply/guidance/utilities/padding.md +155 -0
- package/skills/design-systems-slds-apply/guidance/utilities/position.md +177 -0
- package/skills/design-systems-slds-apply/guidance/utilities/print.md +114 -0
- package/skills/design-systems-slds-apply/guidance/utilities/scrollable.md +126 -0
- package/skills/design-systems-slds-apply/guidance/utilities/sizing.md +190 -0
- package/skills/design-systems-slds-apply/guidance/utilities/themes.md +121 -0
- package/skills/design-systems-slds-apply/guidance/utilities/truncate.md +127 -0
- package/skills/design-systems-slds-apply/guidance/utilities/typography.md +166 -0
- package/skills/design-systems-slds-apply/guidance/utilities/vertical-list.md +166 -0
- package/skills/design-systems-slds-apply/guidance/utilities/visibility.md +228 -0
- package/skills/design-systems-slds-apply/metadata/README.md +84 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/accordion.yaml +304 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/activity-timeline.yaml +92 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/alert.yaml +103 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/app-launcher.yaml +94 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/avatar-group.yaml +81 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/avatar.yaml +97 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/badges.yaml +102 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/brand-band.yaml +198 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/breadcrumbs.yaml +95 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/builder-header.yaml +192 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/button-groups.yaml +82 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/button-icons.yaml +295 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/buttons.yaml +230 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/cards.yaml +124 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/carousel.yaml +140 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/chat.yaml +179 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/checkbox-button.yaml +204 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/checkbox.yaml +108 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/color-picker.yaml +172 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/combobox.yaml +136 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/counter.yaml +147 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/data-tables.yaml +157 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/datepickers.yaml +130 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/datetime-picker.yaml +155 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/docked-composer.yaml +201 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/docked-form-footer.yaml +161 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/drop-zone.yaml +115 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/dueling-picklist.yaml +196 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/dynamic-icons.yaml +128 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/dynamic-menu.yaml +141 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/expandable-section.yaml +115 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/expression.yaml +143 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/feeds.yaml +125 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/file-selector.yaml +154 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/files.yaml +119 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/form-element.yaml +145 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/global-header.yaml +120 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/global-navigation.yaml +100 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/icons.yaml +138 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/illustration.yaml +205 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/input.yaml +151 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/list-builder.yaml +127 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/lookups.yaml +132 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/map.yaml +118 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/menus.yaml +134 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/modals.yaml +152 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/notifications.yaml +88 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/page-headers.yaml +135 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/panels.yaml +149 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/path.yaml +154 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/picklist.yaml +125 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/pills.yaml +154 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/popovers.yaml +120 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/progress-bar.yaml +110 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/progress-indicator.yaml +133 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/progress-ring.yaml +102 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/prompt.yaml +126 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/publishers.yaml +178 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/radio-button-group.yaml +172 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/radio-group.yaml +112 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/rich-text-editor.yaml +135 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/scoped-notifications.yaml +188 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/scoped-tabs.yaml +97 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/select.yaml +127 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/setup-assistant.yaml +152 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/slider.yaml +111 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/spinners.yaml +135 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/split-view.yaml +112 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/summary-detail.yaml +103 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/tabs.yaml +138 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/textarea.yaml +116 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/tiles.yaml +108 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/timepicker.yaml +111 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/toast.yaml +154 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/tooltips.yaml +107 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/tree-grid.yaml +116 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/trees.yaml +116 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/trial-bar.yaml +112 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/vertical-navigation.yaml +130 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/vertical-tabs.yaml +140 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/visual-picker.yaml +150 -0
- package/skills/design-systems-slds-apply/metadata/blueprints/components/welcome-mat.yaml +136 -0
- package/skills/design-systems-slds-apply/metadata/hooks-index.json +6272 -0
- package/skills/design-systems-slds-apply/metadata/icon-metadata.json +38466 -0
- package/skills/design-systems-slds-apply/metadata/utilities-index.json +21912 -0
- package/skills/design-systems-slds-apply/references/component-selection.md +112 -0
- package/skills/design-systems-slds-apply/references/icons-decision-guide.md +124 -0
- package/skills/design-systems-slds-apply/references/styling-decision-guide.md +228 -0
- package/skills/design-systems-slds-apply/references/utilities-quick-ref.md +125 -0
- package/skills/design-systems-slds-apply/scripts/search-blueprints.cjs +117 -0
- package/skills/design-systems-slds-apply/scripts/search-hooks.cjs +139 -0
- package/skills/design-systems-slds-apply/scripts/search-icons.cjs +174 -0
- package/skills/design-systems-slds-apply/scripts/search-utilities.cjs +161 -0
- package/skills/design-systems-slds-validate/SKILL.md +262 -0
- package/skills/design-systems-slds-validate/references/quality-checks.md +308 -0
- package/skills/design-systems-slds-validate/references/report-format.md +302 -0
- package/skills/design-systems-slds-validate/scripts/analyze-quality.cjs +521 -0
- package/skills/design-systems-slds2-migrate/SKILL.md +239 -0
- package/skills/design-systems-slds2-migrate/references/color-hooks-decision-guide.md +459 -0
- package/skills/design-systems-slds2-migrate/references/common-patterns.md +87 -0
- package/skills/design-systems-slds2-migrate/references/examples.md +461 -0
- package/skills/design-systems-slds2-migrate/references/migration-checklist.md +67 -0
- package/skills/design-systems-slds2-migrate/references/non-color-hooks-decision-guide.md +333 -0
- package/skills/design-systems-slds2-migrate/references/rule-lwc-token-to-slds-hook.md +135 -0
- package/skills/design-systems-slds2-migrate/references/rule-no-deprecated-tokens-slds1.md +211 -0
- package/skills/design-systems-slds2-migrate/references/rule-no-hardcoded-values.md +160 -0
- package/skills/design-systems-slds2-migrate/references/rule-no-slds-class-overrides.md +126 -0
- package/skills/dx-app-analytics-query/SKILL.md +135 -0
- package/skills/dx-code-analyzer-configure/SKILL.md +482 -0
- package/skills/dx-code-analyzer-configure/examples/apex-project-config.yml +41 -0
- package/skills/dx-code-analyzer-configure/examples/ci-github-actions.yml +96 -0
- package/skills/dx-code-analyzer-configure/examples/fullstack-project-config.yml +46 -0
- package/skills/dx-code-analyzer-configure/examples/lwc-project-config.yml +26 -0
- package/skills/dx-code-analyzer-configure/references/ci-cd-templates.md +648 -0
- package/skills/dx-code-analyzer-configure/references/config-schema.md +257 -0
- package/skills/dx-code-analyzer-configure/references/diagnostic-flow.md +70 -0
- package/skills/dx-code-analyzer-configure/references/engine-prerequisites.md +276 -0
- package/skills/dx-code-analyzer-configure/references/rule-name-resolution.md +67 -0
- package/skills/dx-code-analyzer-configure/references/troubleshooting.md +298 -0
- package/skills/dx-code-analyzer-configure/scripts/check-prerequisites.sh +189 -0
- package/skills/dx-code-analyzer-configure/scripts/generate-config.sh +143 -0
- package/skills/dx-code-analyzer-configure/scripts/validate-config.sh +153 -0
- package/skills/dx-code-analyzer-run/SKILL.md +495 -0
- package/skills/dx-code-analyzer-run/examples/README.md +38 -0
- package/skills/dx-code-analyzer-run/examples/basic-scan-output.json +92 -0
- package/skills/dx-code-analyzer-run/examples/command-variations.md +333 -0
- package/skills/dx-code-analyzer-run/examples/fix-application-before-after.md +142 -0
- package/skills/dx-code-analyzer-run/examples/large-scan-output.json +67 -0
- package/skills/dx-code-analyzer-run/examples/security-focused-output.json +95 -0
- package/skills/dx-code-analyzer-run/references/command-examples.md +27 -0
- package/skills/dx-code-analyzer-run/references/engine-reference.md +34 -0
- package/skills/dx-code-analyzer-run/references/error-handling.md +29 -0
- package/skills/dx-code-analyzer-run/references/flag-reference.md +96 -0
- package/skills/dx-code-analyzer-run/references/post-scan-workflows.md +286 -0
- package/skills/dx-code-analyzer-run/references/quick-start.md +28 -0
- package/skills/dx-code-analyzer-run/references/special-behaviors.md +83 -0
- package/skills/dx-code-analyzer-run/references/vendor-file-handling.md +239 -0
- package/skills/dx-code-analyzer-run/scripts/apply-fixes.js +86 -0
- package/skills/dx-code-analyzer-run/scripts/describe-rule.js +382 -0
- package/skills/dx-code-analyzer-run/scripts/discover-fixes.js +34 -0
- package/skills/dx-code-analyzer-run/scripts/filter-violations.js +405 -0
- package/skills/dx-code-analyzer-run/scripts/list-rules.js +260 -0
- package/skills/dx-code-analyzer-run/scripts/parse-results.js +59 -0
- package/skills/dx-code-analyzer-run/scripts/query-results.js +230 -0
- package/skills/dx-code-analyzer-run/scripts/summarize-fixes.js +32 -0
- package/skills/dx-code-analyzer-run/scripts/verify-execution.sh +28 -0
- package/skills/dx-org-switch/SKILL.md +28 -0
- package/skills/experience-cms-brand-apply/SKILL.md +170 -0
- package/skills/experience-content-media-search/SKILL.md +348 -0
- package/skills/experience-lwc-generate/CREDITS.md +5 -0
- package/skills/experience-lwc-generate/README.md +126 -0
- package/skills/experience-lwc-generate/SKILL.md +190 -0
- package/skills/experience-lwc-generate/assets/apex-controller/LwcController.cls +327 -0
- package/skills/experience-lwc-generate/assets/basic-component/basicComponent.css +72 -0
- package/skills/experience-lwc-generate/assets/basic-component/basicComponent.html +111 -0
- package/skills/experience-lwc-generate/assets/basic-component/basicComponent.js +163 -0
- package/skills/experience-lwc-generate/assets/basic-component/basicComponent.js-meta.xml +137 -0
- package/skills/experience-lwc-generate/assets/datatable-component/datatableComponent.html +111 -0
- package/skills/experience-lwc-generate/assets/datatable-component/datatableComponent.js +367 -0
- package/skills/experience-lwc-generate/assets/flow-screen-component/flowScreenComponent.css +63 -0
- package/skills/experience-lwc-generate/assets/flow-screen-component/flowScreenComponent.html +154 -0
- package/skills/experience-lwc-generate/assets/flow-screen-component/flowScreenComponent.js +348 -0
- package/skills/experience-lwc-generate/assets/flow-screen-component/flowScreenComponent.js-meta.xml +87 -0
- package/skills/experience-lwc-generate/assets/form-component/formComponent.html +165 -0
- package/skills/experience-lwc-generate/assets/form-component/formComponent.js +275 -0
- package/skills/experience-lwc-generate/assets/graphql-component/graphqlComponent.html +100 -0
- package/skills/experience-lwc-generate/assets/graphql-component/graphqlComponent.js +336 -0
- package/skills/experience-lwc-generate/assets/jest-test/componentName.test.js.example +371 -0
- package/skills/experience-lwc-generate/assets/message-channel/RecordSelected.messageChannel-meta.xml +71 -0
- package/skills/experience-lwc-generate/assets/message-channel/lmsPublisher.js +103 -0
- package/skills/experience-lwc-generate/assets/message-channel/lmsSubscriber.js +181 -0
- package/skills/experience-lwc-generate/assets/modal-component/modalComponent.html +85 -0
- package/skills/experience-lwc-generate/assets/modal-component/modalComponent.js +199 -0
- package/skills/experience-lwc-generate/assets/record-picker/recordPicker.html +55 -0
- package/skills/experience-lwc-generate/assets/record-picker/recordPicker.js +199 -0
- package/skills/experience-lwc-generate/assets/state-store/store.js +282 -0
- package/skills/experience-lwc-generate/assets/typescript-component/typescriptComponent.css +65 -0
- package/skills/experience-lwc-generate/assets/typescript-component/typescriptComponent.html +95 -0
- package/skills/experience-lwc-generate/assets/typescript-component/typescriptComponent.js-meta.xml +75 -0
- package/skills/experience-lwc-generate/assets/typescript-component/typescriptComponent.test.ts.example +301 -0
- package/skills/experience-lwc-generate/assets/typescript-component/typescriptComponent.ts +295 -0
- package/skills/experience-lwc-generate/assets/workspace-api/workspaceComponent.html +71 -0
- package/skills/experience-lwc-generate/assets/workspace-api/workspaceComponent.js +316 -0
- package/skills/experience-lwc-generate/hooks/scripts/lwc-lsp-validate.py +295 -0
- package/skills/experience-lwc-generate/hooks/scripts/post-tool-validate.py +347 -0
- package/skills/experience-lwc-generate/hooks/scripts/slds_data/deprecated_patterns.json +74 -0
- package/skills/experience-lwc-generate/hooks/scripts/slds_data/styling_hooks.json +111 -0
- package/skills/experience-lwc-generate/hooks/scripts/slds_data/valid_slds_classes.json +127 -0
- package/skills/experience-lwc-generate/hooks/scripts/slds_linter_wrapper.py +294 -0
- package/skills/experience-lwc-generate/hooks/scripts/slds_rules/__init__.py +22 -0
- package/skills/experience-lwc-generate/hooks/scripts/template_validator.py +332 -0
- package/skills/experience-lwc-generate/hooks/scripts/validate_slds.py +595 -0
- package/skills/experience-lwc-generate/references/accessibility-guide.md +843 -0
- package/skills/experience-lwc-generate/references/advanced-features.md +108 -0
- package/skills/experience-lwc-generate/references/async-notification-patterns.md +661 -0
- package/skills/experience-lwc-generate/references/cli-commands.md +545 -0
- package/skills/experience-lwc-generate/references/component-patterns.md +1476 -0
- package/skills/experience-lwc-generate/references/flow-integration-guide.md +675 -0
- package/skills/experience-lwc-generate/references/jest-testing.md +1011 -0
- package/skills/experience-lwc-generate/references/lms-guide.md +860 -0
- package/skills/experience-lwc-generate/references/lwc-best-practices.md +1310 -0
- package/skills/experience-lwc-generate/references/performance-guide.md +861 -0
- package/skills/experience-lwc-generate/references/scoring-and-testing.md +116 -0
- package/skills/experience-lwc-generate/references/slds-blueprints.json +14389 -0
- package/skills/experience-lwc-generate/references/slds-design-guide.md +166 -0
- package/skills/experience-lwc-generate/references/state-management.md +642 -0
- package/skills/experience-lwc-generate/references/template-anti-patterns.md +948 -0
- package/skills/experience-lwc-generate/references/triangle-pattern.md +365 -0
- package/skills/experience-lwc-generate/scripts/local-dev-preview.sh +34 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/SKILL.md +280 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/agent-id-resolution.md +46 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/constraints.md +134 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/examples.md +132 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/style-tokens.md +260 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/troubleshooting.md +57 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +350 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +93 -0
- package/skills/experience-ui-bundle-custom-app-generate/docs/configure-metadata-custom-application.md +70 -0
- package/skills/experience-ui-bundle-deploy/SKILL.md +79 -0
- package/skills/experience-ui-bundle-features-generate/SKILL.md +47 -0
- package/skills/experience-ui-bundle-file-upload-generate/SKILL.md +398 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +135 -0
- package/skills/experience-ui-bundle-frontend-generate/implementation/component.md +78 -0
- package/skills/experience-ui-bundle-frontend-generate/implementation/header-footer.md +132 -0
- package/skills/experience-ui-bundle-frontend-generate/implementation/page.md +93 -0
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +153 -0
- package/skills/experience-ui-bundle-metadata-generate/implementation/csp-metadata-format.md +281 -0
- package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +638 -0
- package/skills/experience-ui-bundle-salesforce-data-access/scripts/graphql-search.sh +191 -0
- package/skills/experience-ui-bundle-site-generate/SKILL.md +92 -0
- package/skills/experience-ui-bundle-site-generate/docs/configure-metadata-custom-site.md +41 -0
- package/skills/experience-ui-bundle-site-generate/docs/configure-metadata-digital-experience-bundle.md +17 -0
- package/skills/experience-ui-bundle-site-generate/docs/configure-metadata-digital-experience-config.md +21 -0
- package/skills/experience-ui-bundle-site-generate/docs/configure-metadata-digital-experience.md +40 -0
- package/skills/experience-ui-bundle-site-generate/docs/configure-metadata-network.md +72 -0
- package/skills/experience-ui-bundle-site-generate/docs/update-site-urls.md +100 -0
- package/skills/external-diagram-mermaid-generate/CREDITS.md +46 -0
- package/skills/external-diagram-mermaid-generate/README.md +114 -0
- package/skills/external-diagram-mermaid-generate/SKILL.md +217 -0
- package/skills/external-diagram-mermaid-generate/assets/agentforce/agent-flow.md +313 -0
- package/skills/external-diagram-mermaid-generate/assets/architecture/system-landscape.md +351 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/b2b-commerce-erd.md +317 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/campaigns-erd.md +195 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/consent-erd.md +262 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/files-erd.md +266 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/forecasting-erd.md +261 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/fsl-erd.md +332 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/party-model-erd.md +237 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/quote-order-erd.md +277 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/revenue-cloud-erd.md +343 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/sales-cloud-erd.md +192 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/salesforce-erd.md +209 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/scheduler-erd.md +276 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/service-cloud-erd.md +217 -0
- package/skills/external-diagram-mermaid-generate/assets/datamodel/territory-management-erd.md +241 -0
- package/skills/external-diagram-mermaid-generate/assets/integration/api-sequence.md +387 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code-pkce.md +197 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code.md +152 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/client-credentials.md +233 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/device-authorization.md +295 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/jwt-bearer.md +256 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/refresh-token.md +281 -0
- package/skills/external-diagram-mermaid-generate/assets/oauth/user-agent-social-sign-on.md +281 -0
- package/skills/external-diagram-mermaid-generate/assets/role-hierarchy/user-hierarchy.md +322 -0
- package/skills/external-diagram-mermaid-generate/references/color-palette.md +464 -0
- package/skills/external-diagram-mermaid-generate/references/diagram-conventions.md +313 -0
- package/skills/external-diagram-mermaid-generate/references/erd-conventions.md +320 -0
- package/skills/external-diagram-mermaid-generate/references/mermaid-reference.md +434 -0
- package/skills/external-diagram-mermaid-generate/references/mermaid-styling.md +81 -0
- package/skills/external-diagram-mermaid-generate/references/preview-guide.md +46 -0
- package/skills/external-diagram-mermaid-generate/references/usage-examples.md +340 -0
- package/skills/external-diagram-mermaid-generate/scripts/README.md +160 -0
- package/skills/external-diagram-mermaid-generate/scripts/mermaid_preview.py +654 -0
- package/skills/external-diagram-mermaid-generate/scripts/query-org-metadata.py +293 -0
- package/skills/external-diagram-visual-generate/CREDITS.md +80 -0
- package/skills/external-diagram-visual-generate/README.md +83 -0
- package/skills/external-diagram-visual-generate/SKILL.md +207 -0
- package/skills/external-diagram-visual-generate/assets/architecture/integration-flow.md +55 -0
- package/skills/external-diagram-visual-generate/assets/erd/core-objects.md +131 -0
- package/skills/external-diagram-visual-generate/assets/erd/custom-objects.md +60 -0
- package/skills/external-diagram-visual-generate/assets/lwc/dashboard-card.md +45 -0
- package/skills/external-diagram-visual-generate/assets/lwc/data-table.md +57 -0
- package/skills/external-diagram-visual-generate/assets/lwc/record-form.md +60 -0
- package/skills/external-diagram-visual-generate/assets/review/apex-review.md +57 -0
- package/skills/external-diagram-visual-generate/assets/review/lwc-review.md +48 -0
- package/skills/external-diagram-visual-generate/references/architect-aesthetic-guide.md +257 -0
- package/skills/external-diagram-visual-generate/references/examples-index.md +35 -0
- package/skills/external-diagram-visual-generate/references/gemini-cli-setup.md +65 -0
- package/skills/external-diagram-visual-generate/references/interview-questions.md +529 -0
- package/skills/external-diagram-visual-generate/references/iteration-workflow.md +173 -0
- package/skills/external-diagram-visual-generate/scripts/check-prerequisites.sh +101 -0
- package/skills/external-diagram-visual-generate/scripts/generate_image.py +243 -0
- package/skills/getting-metadata-api-context/README.md +79 -0
- package/skills/getting-metadata-api-context/SKILL.md +466 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AIApplication.json +37 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AIApplicationConfig.json +53 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AIReplyRecommendationsSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AIScoringModelDefinition.json +87 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AIUsecaseDefinition.json +215 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountInsightsSettings.json +30 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountIntelligenceSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountPlanObjMeasCalcDef.json +86 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountPlanSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountRelationshipShareRule.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountSettings.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountingFieldMapping.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountingModelConfig.json +94 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AccountingSettings.json +53 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActionLinkGroupTemplate.json +118 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActionOverride.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActionPlanTemplate.json +166 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActionableListDefinition.json +114 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActionsSettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActivationPlatform.json +95 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActivationPlatformActvAttr.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActivationPlatformField.json +55 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActivitiesSettings.json +136 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActvPfrmDataConnectorS3.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActvPlatformAdncIdentifier.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ActvPlatformFieldValue.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AddressSettings.json +90 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AdvAccountForecastSet.json +261 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AffinityScoreDefinition.json +74 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AgentPlatformSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AgentforceForDevelopersSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AiAuthoringBundle.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AiEvaluationDefinition.json +153 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AiPluginUtteranceDef.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AllOrNoneHeader.json +17 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnalyticSnapshot.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnalyticsDashboard.json +369 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnalyticsSettings.json +488 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnalyticsVisualization.json +180 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnalyticsWorkspace.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AnimationRule.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexClass.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexComponent.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexEmailNotifications.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexPage.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexSettings.json +96 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexTestSuite.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApexTrigger.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppAnalyticsSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppExperienceSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppFrameworkTemplateBundle.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppMenu.json +10 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppointmentAssignmentPolicy.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AppointmentSchedulingPolicy.json +102 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ApprovalProcess.json +234 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ArticleType.json +81 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ArticleType_CustomField.json +88 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ArticleType_Layout.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AssessmentQuestion.json +117 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AssessmentQuestionSet.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AssignmentRules.json +87 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AssociationEngineSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AsyncResult.json +89 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Audience.json +172 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AuraDefinitionBundle.json +94 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AuthProvider.json +169 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AutoResponseRules.json +79 -0
- package/skills/getting-metadata-api-context/data/metadata_api/AutomatedContactsSettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BaseSharingRule.json +24 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BatchCalcJobDefinition.json +849 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BatchProcessJobDefinition.json +175 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BillingSettings.json +152 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BlacklistedConsumer.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Bot.json +197 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BotBlock.json +86 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BotSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BotTemplate.json +96 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BotVersion.json +667 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BranchManagementSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BrandingSet.json +146 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BriefcaseDefinition.json +127 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BusinessHoursSettings.json +175 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BusinessProcess.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/BusinessProcessGroup.json +91 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CMSConnectSource.json +197 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CallCenter.json +124 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CallCenterRoutingMap.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CallCoachingMediaProvider.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CallOptions.json +17 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CampaignInfluenceModel.json +59 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CampaignSettings.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CancelDeployResult.json +10 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CareBenefitVerifySettings.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CareLimitType.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CareProviderSearchConfig.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CareRequestConfiguration.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CareSystemFieldMapping.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CaseSettings.json +423 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CaseSubjectParticle.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CatalogedApi.json +97 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CatalogedApiArtifactVersionInfo.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CatalogedApiVersion.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Certificate.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChannelLayout.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChatterAnswersSettings.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChatterEmailsMDSettings.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChatterExtension.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChatterSettings.json +92 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ChoiceList.json +66 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ClaimFinancialSettings.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ClauseCatgConfiguration.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CleanDataService.json +166 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CodeBuilderSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CollectionsDashboardSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CommerceSettings.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CommunitiesSettings.json +116 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Community.json +121 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CommunityTemplateDefinition.json +116 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CommunityThemeDefinition.json +146 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CompactLayout.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CompanySettings.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConnectedApp.json +384 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConnectedAppSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ContentAsset.json +121 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ContentSettings.json +116 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ContentTypeBundle.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ContextDefinition.json +340 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ContractSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConvIntelligenceSignalRule.json +106 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConversationChannelDefinition.json +140 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConversationMessageDefinition.json +380 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConversationMessageDefinitionTranslation.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConversationVendorInfo.json +148 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ConversationalIntelligenceSettings.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CorsWhitelistOrigin.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CriteriaBasedSharingRule.json +206 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CspTrustedSite.json +82 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CurrencySettings.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomAddressFieldSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomApplication.json +453 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomApplicationComponent.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomFeedFilter.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomField.json +392 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomFieldDisplay.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomHelpMenuSection.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomIndex.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomLabels.json +69 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomMetadata.json +90 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomNotificationType.json +94 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomObject.json +313 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomObjectTranslation.json +319 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomPageWebLink.json +121 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomPermission.json +65 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomSite.json +288 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomTab.json +97 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomValue.json +85 -0
- package/skills/getting-metadata-api-context/data/metadata_api/CustomerDataPlatformSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Dashboard.json +584 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataCategoryGroup.json +81 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataConnector.json +230 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataConnectorIngestApi.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataConnectorS3.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataDotComSettings.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataImportManagementSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataKitObjectDependency.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataKitObjectTemplate.json +59 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataObjectBuildOrgTemplate.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataObjectSearchIndexConf.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataPackageKitDefinition.json +74 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataPackageKitObject.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSource.json +29 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSourceBundleDefinition.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSourceField.json +115 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSourceObject.json +93 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSourceTenant.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataSrcDataModelFieldMap.json +69 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataStreamDefinition.json +105 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataStreamTemplate.json +99 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DataWeaveResource.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DebuggingHeader.json +20 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DecisionMatrixDefinition.json +140 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DecisionTable.json +211 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DecisionTableDatasetLink.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DelegateGroup.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DeleteResult.json +22 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DeployResult.json +253 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DeploymentSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DescribeMetadataResult.json +31 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DescribeValueTypeResult.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DevHubSettings.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DgtAssetMgmtProvider.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DgtAssetMgmtPrvdLghtCpnt.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DigitalExperienceBundle.json +102 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DigitalExperienceBundle_Marketing_Workspace_Bundle_and_Folders.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DigitalExperienceBundle_Site_Workspace_Bundle_and_Folders.json +541 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DigitalExperienceConfig.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DisclosureDefinition.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DisclosureDefinitionVersion.json +78 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DisclosureType.json +53 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DiscoveryAIModel.json +263 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DiscoveryGoal.json +361 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DiscoveryStory.json +98 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Document.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DocumentCategory.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DocumentCategoryDocumentType.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DocumentChecklistSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DocumentGenerationSetting.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DocumentType.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DuplicateRule.json +160 -0
- package/skills/getting-metadata-api-context/data/metadata_api/DynamicFormsSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EACSettings.json +112 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EclairGeoData.json +73 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EinsteinAISettings.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EinsteinAgentSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EinsteinGptSettings.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailAdministrationSettings.json +104 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailAuthorizationSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailIntegrationSettings.json +92 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailServicesFunction.json +116 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailTemplate.json +116 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmailTemplateSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceBranding.json +78 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceConfig.json +318 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceFieldService.json +73 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceFlowConfig.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceLiveAgent.json +141 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmbeddedServiceMenuSettings.json +165 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EmployeeUserSettings.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EnablementMeasureDefinition.json +139 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EnablementProgramDefinition.json +241 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EnblProgramTaskSubCategory.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EncryptionKeySettings.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EnhancedNotesSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EntitlementProcess.json +147 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EntitlementSettings.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EntitlementTemplate.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Error.json +25 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EscalationRules.json +117 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EventDelivery.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EventRelayConfig.json +55 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EventSettings.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/EventSubscription.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExperienceBundle.json +387 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExperienceBundleSettings.json +25 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExperiencePropertyTypeBundle.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExplainabilityMsgTemplate.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExpressionSetDefinition.json +496 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExpressionSetMessageToken.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExpressionSetObjectAlias.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalAIModel.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalAuthIdentityProvider.json +79 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalClientAppSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalClientApplication.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalCredential.json +94 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalDataConnector.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalDataSource.json +162 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalDataTranObject.json +191 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalDataTransportFieldTemplate.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalDataTransportObjectTemplate.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalServiceRegistration.json +121 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExternalServicesSettings.json +34 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppCanvasSettings.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppConfigurablePolicies.json +75 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppGlobalOauthSettings.json +135 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppMobileConfigurablePolicies.json +34 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppMobileSettings.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppNotificationSettings.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppOauthConfigurablePolicies.json +153 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppOauthSettings.json +120 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppPushConfigurablePolicies.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppPushSettings.json +93 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ExtlClntAppSamlConfigurablePolicies.json +119 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FeatureParameterBoolean.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FeatureParameterDate.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FeatureParameterInteger.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FieldMappingConfig.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FieldRestrictionRule.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FieldServiceSettings.json +226 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FieldSet.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FieldSrcTrgtRelationship.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FileUploadAndDownloadSecuritySettings.json +53 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FilesConnectSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlexiPage.json +355 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Flow.json +2377 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlowCategory.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlowDefinition.json +37 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlowSettings.json +124 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlowTest.json +205 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FlowValueMap.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Folder.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FolderShare.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingFilter.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingFilterCondition.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingObjectListSettings.json +77 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingSettings.json +303 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingSourceDefinition.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingType.json +100 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ForecastingTypeSource.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FuelType.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FuelTypeSustnUom.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FunctionReference.json +31 -0
- package/skills/getting-metadata-api-context/data/metadata_api/FundraisingConfig.json +86 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GatewayProviderPaymentMethodType.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiFunction.json +171 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPlanner.json +215 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPlannerBundle.json +220 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPlugin.json +87 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPluginInstructionDef.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPromptTemplate.json +183 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GenAiPromptTemplateActv.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GiftEntryGridTemplate.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GlobalPicklist.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GlobalPicklistValue.json +81 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GlobalValueSet.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GlobalValueSetTranslation.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/GoogleAppsSettings.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Group.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/HighVelocitySalesSettings.json +96 -0
- package/skills/getting-metadata-api-context/data/metadata_api/HistoryRetentionPolicy.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/HomePageComponent.json +66 -0
- package/skills/getting-metadata-api-context/data/metadata_api/HomePageLayout.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IPAddressRange.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IdeasSettings.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IdentityProviderSettings.json +39 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IdentityVerificationProcDef.json +173 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IdentityVerificationProcDtl.json +136 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IdentityVerificationProcFld.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IframeWhiteListUrlSettings.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InboundCertificate.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InboundNetworkConnection.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IncidentMgmtSettings.json +140 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Index.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesEinsteinFeatureSettings.json +34 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesLoyaltySettings.json +108 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesPricingSettings.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesRatingSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesSettings.json +731 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IndustriesUnifiedInventorySettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InsPlcyLimitConsumptionRule.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InstalledPackage.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IntegArtifactDef.json +10 -0
- package/skills/getting-metadata-api-context/data/metadata_api/IntegrationProviderDef.json +155 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InterestTaggingSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InternalDataConnector.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InvLatePymntRiskCalcSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InventorySettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InvocableActionExtension.json +84 -0
- package/skills/getting-metadata-api-context/data/metadata_api/InvocableActionSettings.json +28 -0
- package/skills/getting-metadata-api-context/data/metadata_api/KeywordList.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/KnowledgeSettings.json +280 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LanguageSettings.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Layout.json +659 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LeadConfigSettings.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LeadConvertSettings.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LearningItemType.json +65 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Letterhead.json +119 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningBolt.json +103 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningComponentBundle.json +109 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningExperienceSettings.json +191 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningExperienceTheme.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningMessageChannel.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningOnboardingConfig.json +62 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LightningTypeBundle.json +88 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ListMetadataQuery.json +10 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ListView.json +86 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveAgentSettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveChatAgentConfig.json +188 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveChatButton.json +188 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveChatDeployment.json +81 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveChatSensitiveDataRule.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LiveMessageSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/LoyaltyProgramSetup.json +297 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MLDataDefinition.json +146 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MLPredictionDefinition.json +67 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MacroSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MailMergeSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ManagedContentType.json +86 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ManagedEventSubscription.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ManagedTopics.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MapAndLocationSettings.json +34 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MarketSegmentDefinition.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MarketingAppExtension.json +139 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MatchingRule.json +69 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MeetingsSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MessagingChannel.json +278 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MetadataWithContent.json +24 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Metadata_Type_Limits.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MfgProgramTemplate.json +88 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MfgServiceConsoleSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MilestoneType.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MktCalcInsightObjectDef.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MktDataTranObject.json +99 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MlDomain.json +136 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MobSecurityCertPinConfig.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MobileApplicationDetail.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MobileSecurityAssignment.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MobileSecurityPolicy.json +75 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MobileSettings.json +121 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ModerationRule.json +99 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MutingPermissionSet.json +33 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MyDomainDiscoverableLogin.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/MyDomainSettings.json +140 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NameSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NamedCredential.json +205 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NamedFilter.json +89 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NavigationMenu.json +101 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Network.json +606 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NetworkBranding.json +117 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NotificationTypeConfig.json +75 -0
- package/skills/getting-metadata-api-context/data/metadata_api/NotificationsSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OauthCustomScope.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OauthOidcSettings.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OauthTokenExchangeHandler.json +119 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ObjectHierarchyRelationship.json +108 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ObjectLinkingSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ObjectSourceTargetMap.json +85 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OcrSampleDocument.json +158 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OcrTemplate.json +180 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniChannelSettings.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniExtTrackingDef.json +66 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniInteractionAccessConfig.json +90 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniInteractionConfig.json +37 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniScript.json +204 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniSupervisorConfig.json +156 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OmniTrackingGroup.json +77 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OnboardingDataObjectGroup.json +131 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OpportunityInsightsSettings.json +30 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OpportunityScoreSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OpportunitySettings.json +132 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OrchestrationPlanCtxMapping.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OrderManagementSettings.json +52 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OrderSettings.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OrgPreferenceSettings.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OrgSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OutboundNetworkConnection.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/OwnerSharingRule.json +206 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Package.json +19 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PardotEinsteinSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PardotSettings.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ParticipantRole.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PartyDataModelSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PathAssistant.json +74 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PathAssistantSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PaymentGatewayProvider.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PaymentsSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PermissionSet.json +372 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PermissionSetGroup.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PermissionSetLicenseDefinition.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PersonAccountOwnerPowerUser.json +38 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Picklist.json +43 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PicklistSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PipelineInspMetricConfig.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformCachePartition.json +79 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEncryptionSettings.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEventChannel.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEventChannelMember.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEventMigration.json +39 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEventSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PlatformEventSubscriberConfig.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Portal.json +137 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PortalDelegablePermissionSet.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PostTemplate.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PredictionBuilderSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PresenceDeclineReason.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PresenceUserConfig.json +122 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PricingActionParameters.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PricingRecipe.json +117 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PrivacySettings.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProcessFlowMigration.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProductAttributeSet.json +33 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProductSettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Profile.json +492 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProfileActionOverride.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProfilePasswordPolicy.json +80 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProfileSearchLayouts.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ProfileSessionSetting.json +55 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Prompt.json +255 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PublicKeyCertificate.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/PublicKeyCertificateSet.json +65 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Queue.json +123 -0
- package/skills/getting-metadata-api-context/data/metadata_api/QueueRoutingConfig.json +96 -0
- package/skills/getting-metadata-api-context/data/metadata_api/QuickAction.json +175 -0
- package/skills/getting-metadata-api-context/data/metadata_api/QuoteSettings.json +36 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ReadResult.json +16 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RealTimeEventSettings.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecommendationStrategy.json +327 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecordActionDeployment.json +184 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecordAggregationDefinition.json +148 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecordAlertCategory.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecordPageSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RecordType.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RedirectWhitelistUrl.json +26 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ReferencedDashboard.json +55 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RegisteredExternalService.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RelatedRecordAssocCriteria.json +75 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RelationshipGraphDefinition.json +63 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RemoteSiteSetting.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Report.json +715 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ReportType.json +118 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RestrictionRule.json +71 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RetailExecutionSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RetrievalSummaryDefinition.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RetrieveRequest.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RetrieveResult.json +103 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Role.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/RoleOrTerritory.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SalesAgreementSettings.json +180 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SalesWorkQueueSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SamlSsoConfig.json +128 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SandboxSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SaveResult.json +22 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SchedulingObjective.json +66 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SchedulingRule.json +66 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SchemaSettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Scontrol.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SearchCustomization.json +120 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SearchLayouts.json +64 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SearchOrgWideObjectConfig.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SearchSettings.json +155 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SecuritySettings.json +437 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceAISetupDefinition.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceAISetupField.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceChannel.json +123 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceCloudVoiceSettings.json +83 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServicePresenceStatus.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceProcess.json +141 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ServiceSetupAssistantSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SessionHeader.json +17 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharedTo.json +105 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingBaseRule.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingReason.json +34 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingRecalculation.json +29 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingRules.json +186 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingSet.json +78 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SharingSettings.json +92 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SiteDotCom.json +37 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SiteSettings.json +60 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Skill.json +69 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SocialCustomerServiceSettings.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SocialProfileSettings.json +35 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SourceTrackingSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StageAssignment.json +113 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StageDefinition.json +237 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StandardValueSet.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StandardValueSetTranslation.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StaticResource.json +49 -0
- package/skills/getting-metadata-api-context/data/metadata_api/StreamingAppDataConnector.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SubscriptionManagementSettings.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SurveySettings.json +44 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SustainabilityUom.json +61 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SustnUomConversion.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SvcCatalogCategory.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SvcCatalogFulfillmentFlow.json +99 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SvcCatalogItemDef.json +202 -0
- package/skills/getting-metadata-api-context/data/metadata_api/SynonymDictionary.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Tag.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TagSet.json +47 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory.json +39 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory2.json +112 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory2Model.json +41 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory2Rule.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory2Settings.json +111 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Territory2Type.json +42 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TimeSheetTemplate.json +75 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TimelineObjectDefinition.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TopicsForObjects.json +38 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TrailheadSettings.json +40 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TransactionSecurityPolicy.json +127 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Translations.json +976 -0
- package/skills/getting-metadata-api-context/data/metadata_api/TrialOrgSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UIBundle.json +54 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UIObjectRelationConfig.json +101 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UiFormatSpecificationSet.json +103 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UiPreviewMessageTabDef.json +70 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UpsertResult.json +25 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserAccessPolicy.json +120 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserAuthCertificate.json +57 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserCriteria.json +48 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserEngagementSettings.json +136 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserInterfaceSettings.json +96 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserManagementSettings.json +108 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserProfileSearchScope.json +8 -0
- package/skills/getting-metadata-api-context/data/metadata_api/UserProvisioningConfig.json +72 -0
- package/skills/getting-metadata-api-context/data/metadata_api/ValidationRule.json +51 -0
- package/skills/getting-metadata-api-context/data/metadata_api/VirtualVisitConfig.json +97 -0
- package/skills/getting-metadata-api-context/data/metadata_api/VoiceSettings.json +68 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WarrantyLifeCycleMgmtSettings.json +32 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveAnalyticAssetCollection.json +73 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveApplication.json +56 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveComponent.json +46 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveDashboard.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveDataflow.json +45 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveDataset.json +50 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveLens.json +59 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveRecipe.json +58 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveTemplateBundle.json +37 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WaveXmd.json +567 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WebLink.json +117 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WebStoreBundle.json +10 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WebStoreTemplate.json +166 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WorkDotComSettings.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WorkSkillRouting.json +76 -0
- package/skills/getting-metadata-api-context/data/metadata_api/Workflow.json +415 -0
- package/skills/getting-metadata-api-context/data/metadata_api/WorkforceEngagementSettings.json +56 -0
- package/skills/getting-metadata-api-context/examples/README.md +169 -0
- package/skills/getting-metadata-api-context/examples/bash_section_loading.sh +142 -0
- package/skills/getting-metadata-api-context/examples/javascript_section_loading.js +162 -0
- package/skills/getting-metadata-api-context/examples/python_section_loading.py +112 -0
- package/skills/getting-metadata-api-context/references/metadata_index_table.md +654 -0
- package/skills/getting-metadata-api-context/references/usage_guide.md +420 -0
- package/skills/integration-connectivity-connected-app-configure/CREDITS.md +3 -0
- package/skills/integration-connectivity-connected-app-configure/README.md +99 -0
- package/skills/integration-connectivity-connected-app-configure/SKILL.md +223 -0
- package/skills/integration-connectivity-connected-app-configure/assets/connected-app-basic.xml +29 -0
- package/skills/integration-connectivity-connected-app-configure/assets/connected-app-canvas.xml +62 -0
- package/skills/integration-connectivity-connected-app-configure/assets/connected-app-jwt.xml +49 -0
- package/skills/integration-connectivity-connected-app-configure/assets/connected-app-oauth.xml +65 -0
- package/skills/integration-connectivity-connected-app-configure/assets/eca-global-oauth.xml +36 -0
- package/skills/integration-connectivity-connected-app-configure/assets/eca-oauth-settings.xml +36 -0
- package/skills/integration-connectivity-connected-app-configure/assets/eca-policies.xml +36 -0
- package/skills/integration-connectivity-connected-app-configure/assets/external-client-app.xml +35 -0
- package/skills/integration-connectivity-connected-app-configure/references/example-usage.md +256 -0
- package/skills/integration-connectivity-connected-app-configure/references/migration-guide.md +328 -0
- package/skills/integration-connectivity-connected-app-configure/references/oauth-flows-reference.md +660 -0
- package/skills/integration-connectivity-connected-app-configure/references/security-checklist.md +209 -0
- package/skills/integration-connectivity-connected-app-configure/references/testing-validation-guide.md +275 -0
- package/skills/integration-connectivity-generate/CREDITS.md +5 -0
- package/skills/integration-connectivity-generate/README.md +95 -0
- package/skills/integration-connectivity-generate/SKILL.md +191 -0
- package/skills/integration-connectivity-generate/assets/callouts/callout-retry-handler.cls +167 -0
- package/skills/integration-connectivity-generate/assets/callouts/http-response-handler.cls +257 -0
- package/skills/integration-connectivity-generate/assets/callouts/rest-queueable-callout.cls +262 -0
- package/skills/integration-connectivity-generate/assets/callouts/rest-sync-callout.cls +211 -0
- package/skills/integration-connectivity-generate/assets/cdc/cdc-handler.cls +246 -0
- package/skills/integration-connectivity-generate/assets/cdc/cdc-subscriber-trigger.trigger +139 -0
- package/skills/integration-connectivity-generate/assets/endpoint-security/example.cspTrustedSite-meta.xml +58 -0
- package/skills/integration-connectivity-generate/assets/endpoint-security/example.remoteSite-meta.xml +39 -0
- package/skills/integration-connectivity-generate/assets/external-credentials/jwt-external-credential.externalCredential-meta.xml +90 -0
- package/skills/integration-connectivity-generate/assets/external-credentials/oauth-external-credential.externalCredential-meta.xml +87 -0
- package/skills/integration-connectivity-generate/assets/external-services/external-service-operations.md +221 -0
- package/skills/integration-connectivity-generate/assets/external-services/openapi-registration.externalServiceRegistration-meta.xml +193 -0
- package/skills/integration-connectivity-generate/assets/named-credentials/certificate-auth.namedCredential-meta.xml +62 -0
- package/skills/integration-connectivity-generate/assets/named-credentials/custom-auth.namedCredential-meta.xml +71 -0
- package/skills/integration-connectivity-generate/assets/named-credentials/oauth-client-credentials.namedCredential-meta.xml +51 -0
- package/skills/integration-connectivity-generate/assets/named-credentials/oauth-jwt-bearer.namedCredential-meta.xml +67 -0
- package/skills/integration-connectivity-generate/assets/platform-events/event-publisher.cls +191 -0
- package/skills/integration-connectivity-generate/assets/platform-events/event-subscriber-action.cls +295 -0
- package/skills/integration-connectivity-generate/assets/platform-events/event-subscriber-trigger.trigger +108 -0
- package/skills/integration-connectivity-generate/assets/platform-events/platform-event-definition.object-meta.xml +124 -0
- package/skills/integration-connectivity-generate/assets/soap/soap-callout-service.cls +186 -0
- package/skills/integration-connectivity-generate/assets/soap/wsdl2apex-guide.md +213 -0
- package/skills/integration-connectivity-generate/hooks/scripts/suggest_credential_setup.py +271 -0
- package/skills/integration-connectivity-generate/hooks/scripts/validate_integration.py +363 -0
- package/skills/integration-connectivity-generate/references/callout-patterns.md +719 -0
- package/skills/integration-connectivity-generate/references/cdc-guide.md +288 -0
- package/skills/integration-connectivity-generate/references/cli-reference.md +94 -0
- package/skills/integration-connectivity-generate/references/event-driven-architecture-guide.md +266 -0
- package/skills/integration-connectivity-generate/references/event-patterns.md +838 -0
- package/skills/integration-connectivity-generate/references/external-services-guide.md +303 -0
- package/skills/integration-connectivity-generate/references/messaging-api-v2.md +609 -0
- package/skills/integration-connectivity-generate/references/named-credentials-automation.md +201 -0
- package/skills/integration-connectivity-generate/references/named-credentials-guide.md +173 -0
- package/skills/integration-connectivity-generate/references/platform-events-guide.md +288 -0
- package/skills/integration-connectivity-generate/references/rest-callout-patterns.md +288 -0
- package/skills/integration-connectivity-generate/references/scoring-rubric.md +59 -0
- package/skills/integration-connectivity-generate/references/security-best-practices.md +248 -0
- package/skills/integration-connectivity-generate/scripts/README.md +100 -0
- package/skills/integration-connectivity-generate/scripts/configure-named-credential.sh +236 -0
- package/skills/integration-connectivity-generate/scripts/set-api-credential.sh +146 -0
- package/skills/integration-connectivity-generate/scripts/templates/setup-credentials-with-csp.sh +158 -0
- package/skills/integration-eventing-cdc-configure/SKILL.md +164 -0
- package/skills/integration-eventing-cdc-configure/assets/PlatformEventChannel-template.xml +5 -0
- package/skills/integration-eventing-cdc-configure/assets/PlatformEventChannelMember-template.xml +11 -0
- package/skills/integration-eventing-cdc-configure/references/deploy-troubleshooting.md +73 -0
- package/skills/integration-eventing-cdc-configure/references/filter-expressions.md +93 -0
- package/skills/integration-eventing-subscription-configure/SKILL.md +152 -0
- package/skills/integration-eventing-subscription-configure/assets/managed-event-subscription-template.xml +20 -0
- package/skills/integration-eventing-subscription-configure/references/delete-guide.md +57 -0
- package/skills/integration-eventing-subscription-configure/references/topic-name-formats.md +26 -0
- package/skills/integration-eventing-subscription-configure/references/update-constraints.md +30 -0
- package/skills/managing-suite-assignments/SKILL.md +1 -1
- package/skills/mobile-apps-create/SKILL.md +69 -0
- package/skills/mobile-platform-native-capabilities-integrate/SKILL.md +181 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/app-review.md +68 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/ar-space-capture.md +125 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/barcode-scanner.md +219 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/base-capability.md +22 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/biometrics.md +90 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/calendar.md +213 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/contacts.md +232 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/document-scanner.md +342 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/geofencing.md +123 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/location.md +158 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/mobile-capabilities.md +30 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/nfc.md +181 -0
- package/skills/mobile-platform-native-capabilities-integrate/references/payments.md +95 -0
- package/skills/mobile-platform-offline-validate/SKILL.md +167 -0
- package/skills/mobile-platform-offline-validate/references/grounding.md +7 -0
- package/skills/mobile-platform-offline-validate/references/inline-graphql.md +43 -0
- package/skills/mobile-platform-offline-validate/references/komaci-eslint.md +125 -0
- package/skills/mobile-platform-offline-validate/references/lwc-if.md +78 -0
- package/skills/mobile-platform-offline-validate/scripts/komaci.config.mjs +18 -0
- package/skills/mobile-platform-offline-validate/scripts/package.json +10 -0
- package/skills/mobile-platform-offline-validate/scripts/run-komaci.sh +69 -0
- package/skills/omnistudio-callable-apex-generate/CREDITS.md +9 -0
- package/skills/omnistudio-callable-apex-generate/README.md +80 -0
- package/skills/omnistudio-callable-apex-generate/SKILL.md +275 -0
- package/skills/omnistudio-callable-apex-generate/assets/pattern_callable_openinterface.cls +40 -0
- package/skills/omnistudio-callable-apex-generate/assets/pattern_callable_vanilla.cls +32 -0
- package/skills/omnistudio-callable-apex-generate/assets/pattern_migration.cls +54 -0
- package/skills/omnistudio-callable-apex-generate/assets/pattern_openinterface.cls +45 -0
- package/skills/omnistudio-callable-apex-generate/assets/pattern_test_class.cls +65 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_QuoteByProductCallable/IndustriesCallableException.cls +7 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallable.cls +115 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_QuoteByProductCallable/Industries_QuoteByProductCallableTest.cls +189 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_QuoteByProductCallable/TRANSCRIPT.md +115 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/IndustriesCallableException.cls +7 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallable.cls +74 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/MyCustomCallableTest.cls +146 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/MyCustomRemoteClass.cls +16 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md +120 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/IndustriesCallableException.cls +7 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallable.cls +73 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/MyCustomCallableTest.cls +128 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/MyCustomVlocityOpenInterface2.cls +23 -0
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md +75 -0
- package/skills/omnistudio-datamapper-generate/CREDITS.md +5 -0
- package/skills/omnistudio-datamapper-generate/SKILL.md +269 -0
- package/skills/omnistudio-datamapper-generate/assets/completion-summary-template.md +28 -0
- package/skills/omnistudio-datamapper-generate/assets/omni-data-transform-extract.json +6 -0
- package/skills/omnistudio-datamapper-generate/assets/omni-data-transform-item.json +12 -0
- package/skills/omnistudio-datamapper-generate/assets/omni-data-transform-load.json +6 -0
- package/skills/omnistudio-datamapper-generate/assets/omni-data-transform-transform.json +6 -0
- package/skills/omnistudio-datamapper-generate/references/best-practices.md +277 -0
- package/skills/omnistudio-datamapper-generate/references/naming-conventions.md +145 -0
- package/skills/omnistudio-datapacks-deploy/CREDITS.md +5 -0
- package/skills/omnistudio-datapacks-deploy/README.md +88 -0
- package/skills/omnistudio-datapacks-deploy/SKILL.md +173 -0
- package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle/TRANSCRIPT.md +124 -0
- package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle/deploy-business-internet-plus-bundle.yaml +11 -0
- package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle-deploy/TRANSCRIPT.md +142 -0
- package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle-deploy/deploy-business-internet-plus-bundle.yaml +10 -0
- package/skills/omnistudio-datapacks-deploy/references/job-file-template.md +42 -0
- package/skills/omnistudio-datapacks-deploy/references/troubleshooting-matrix.md +24 -0
- package/skills/omnistudio-dependencies-analyze/CREDITS.md +5 -0
- package/skills/omnistudio-dependencies-analyze/SKILL.md +476 -0
- package/skills/omnistudio-dependencies-analyze/references/dependency-patterns.md +508 -0
- package/skills/omnistudio-dependencies-analyze/references/namespace-guide.md +300 -0
- package/skills/omnistudio-epc-catalog-generate/CREDITS.md +14 -0
- package/skills/omnistudio-epc-catalog-generate/README.md +89 -0
- package/skills/omnistudio-epc-catalog-generate/SKILL.md +394 -0
- package/skills/omnistudio-epc-catalog-generate/assets/attribute-assignment-template.json +402 -0
- package/skills/omnistudio-epc-catalog-generate/assets/compiled-attribute-overrides-template.json +43 -0
- package/skills/omnistudio-epc-catalog-generate/assets/completion-block-template.txt +8 -0
- package/skills/omnistudio-epc-catalog-generate/assets/decomposition-relationships-template.json +233 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_AttributeAssignments.json +514 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_CompiledAttributeOverrides.json +21 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DataPack.json +649 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_DecompositionRelationships.json +200 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ObjectFieldAttributes.json +138 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OrchestrationScenarios.json +54 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_OverrideDefinitions.json +266 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ParentKeys.json +23 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PriceListEntries.json +54 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_PricebookEntries.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_ProductChildItems.json +34 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-premium-fttc-simple-offer/Business-Internet-Premium-FTTC_RuleAssignments.json +21 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_AttributeAssignments.json +410 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DataPack.json +535 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_DecompositionRelationships.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ObjectFieldAttributes.json +138 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_OrchestrationScenarios.json +28 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ParentKeys.json +23 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PriceListEntries.json +220 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_PricebookEntries.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/business-internet-pro-vpl-simple-offer/Business-Internet-Pro-VPL_ProductChildItems.json +414 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_AttributeAssignments.json +382 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DataPack.json +565 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_DecompositionRelationships.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ObjectFieldAttributes.json +104 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_OrchestrationScenarios.json +28 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ParentKeys.json +13 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PriceListEntries.json +106 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_PricebookEntries.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/samsung-galaxy-s22-bundle/Samsung-Galaxy-S22-Bundle_ProductChildItems.json +72 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_AttributeAssignments.json +142 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_DataPack.json +377 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_DecompositionRelationships.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_ObjectFieldAttributes.json +36 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_ParentKeys.json +8 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_PriceListEntries.json +54 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_PricebookEntries.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/examples/static-ip-simple-offer/Static-IP_ProductChildItems.json +34 -0
- package/skills/omnistudio-epc-catalog-generate/assets/object-field-attributes-template.json +138 -0
- package/skills/omnistudio-epc-catalog-generate/assets/orchestration-scenarios-template.json +54 -0
- package/skills/omnistudio-epc-catalog-generate/assets/override-definitions-template.json +134 -0
- package/skills/omnistudio-epc-catalog-generate/assets/parent-keys-template.json +29 -0
- package/skills/omnistudio-epc-catalog-generate/assets/price-list-entries-template.json +158 -0
- package/skills/omnistudio-epc-catalog-generate/assets/pricebook-entries-template.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/assets/product-child-item-template.json +338 -0
- package/skills/omnistudio-epc-catalog-generate/assets/product2-offer-template.json +527 -0
- package/skills/omnistudio-epc-catalog-generate/examples/.gitkeep +1 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_AttributeAssignments.json +95 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_CompiledAttributeOverrides.json +1 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_DataPack.json +214 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_DecompositionRelationships.json +28 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_ObjectFieldAttributes.json +98 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_OrchestrationScenarios.json +22 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_OverrideDefinitions.json +1 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_ParentKeys.json +13 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_PriceListEntries.json +35 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_PricebookEntries.json +28 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/Business-Internet-Plus_ProductChildItems.json +110 -0
- package/skills/omnistudio-epc-catalog-generate/examples/business-internet-plus-bundle/TRANSCRIPT.md +58 -0
- package/skills/omnistudio-epc-catalog-generate/references/epc-field-guide.md +90 -0
- package/skills/omnistudio-epc-catalog-generate/references/naming-conventions.md +80 -0
- package/skills/omnistudio-epc-catalog-generate/references/scoring-model.md +57 -0
- package/skills/omnistudio-epc-catalog-generate/scripts/cli-validation-commands.sh +19 -0
- package/skills/omnistudio-epc-catalog-generate/scripts/sample-invocations.sh +18 -0
- package/skills/omnistudio-flexcard-generate/CREDITS.md +5 -0
- package/skills/omnistudio-flexcard-generate/SKILL.md +324 -0
- package/skills/omnistudio-flexcard-generate/assets/omni-ui-card.json +10 -0
- package/skills/omnistudio-flexcard-generate/references/best-practices.md +291 -0
- package/skills/omnistudio-flexcard-generate/references/data-binding-guide.md +311 -0
- package/skills/omnistudio-flexcard-generate/references/scoring-rubric.md +66 -0
- package/skills/omnistudio-flexcard-generate/scripts/flexcard-commands.sh +24 -0
- package/skills/omnistudio-integration-procedure-generate/CREDITS.md +5 -0
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +274 -0
- package/skills/omnistudio-integration-procedure-generate/assets/omni-process-element-dr-extract.json +10 -0
- package/skills/omnistudio-integration-procedure-generate/assets/omni-process-element-set-values.json +10 -0
- package/skills/omnistudio-integration-procedure-generate/assets/omni-process-ip.json +12 -0
- package/skills/omnistudio-integration-procedure-generate/assets/scoring-report-format.txt +14 -0
- package/skills/omnistudio-integration-procedure-generate/references/best-practices.md +388 -0
- package/skills/omnistudio-integration-procedure-generate/references/element-types.md +588 -0
- package/skills/omnistudio-integration-procedure-generate/scripts/cli-commands.sh +18 -0
- package/skills/omnistudio-omniscript-generate/CREDITS.md +5 -0
- package/skills/omnistudio-omniscript-generate/SKILL.md +366 -0
- package/skills/omnistudio-omniscript-generate/assets/omni-process-element-step.json +10 -0
- package/skills/omnistudio-omniscript-generate/assets/omni-process-element-text-block.json +11 -0
- package/skills/omnistudio-omniscript-generate/assets/omni-process-omniscript.json +12 -0
- package/skills/omnistudio-omniscript-generate/references/best-practices.md +480 -0
- package/skills/omnistudio-omniscript-generate/references/element-types.md +1172 -0
- package/skills/omnistudio-omniscript-generate/scripts/check-duplicate-omniscript.sh +13 -0
- package/skills/omnistudio-omniscript-generate/scripts/cli-reference.sh +21 -0
- package/skills/omnistudio-omniscript-generate/scripts/deploy-omniscript.sh +29 -0
- package/skills/platform-agentexchange-partner-offers-configure/SKILL.md +111 -0
- package/skills/platform-agentexchange-partner-offers-configure/assets/org-pref-template.md +27 -0
- package/skills/platform-agentexchange-partner-offers-configure/examples/org-preference-settings.xml +4 -0
- package/skills/platform-apex-generate/CREDITS.md +5 -0
- package/skills/platform-apex-generate/SKILL.md +409 -0
- package/skills/platform-apex-generate/assets/abstract.cls +131 -0
- package/skills/platform-apex-generate/assets/batch.cls +124 -0
- package/skills/platform-apex-generate/assets/domain.cls +101 -0
- package/skills/platform-apex-generate/assets/dto.cls +107 -0
- package/skills/platform-apex-generate/assets/exception.cls +50 -0
- package/skills/platform-apex-generate/assets/interface.cls +24 -0
- package/skills/platform-apex-generate/assets/invocable.cls +114 -0
- package/skills/platform-apex-generate/assets/queueable.cls +91 -0
- package/skills/platform-apex-generate/assets/rest-resource.cls +300 -0
- package/skills/platform-apex-generate/assets/schedulable.cls +74 -0
- package/skills/platform-apex-generate/assets/selector.cls +91 -0
- package/skills/platform-apex-generate/assets/service.cls +68 -0
- package/skills/platform-apex-generate/assets/trigger.cls +45 -0
- package/skills/platform-apex-generate/assets/utility.cls +96 -0
- package/skills/platform-apex-generate/references/AccountDeduplicationBatch.cls +147 -0
- package/skills/platform-apex-generate/references/AccountSelector.cls +192 -0
- package/skills/platform-apex-generate/references/AccountService.cls +200 -0
- package/skills/platform-apex-logs-debug/CREDITS.md +22 -0
- package/skills/platform-apex-logs-debug/README.md +74 -0
- package/skills/platform-apex-logs-debug/SKILL.md +171 -0
- package/skills/platform-apex-logs-debug/assets/benchmarking-template.cls +327 -0
- package/skills/platform-apex-logs-debug/assets/cpu-heap-optimization.cls +307 -0
- package/skills/platform-apex-logs-debug/assets/dml-in-loop-fix.cls +219 -0
- package/skills/platform-apex-logs-debug/assets/null-pointer-fix.cls +252 -0
- package/skills/platform-apex-logs-debug/assets/soql-in-loop-fix.cls +157 -0
- package/skills/platform-apex-logs-debug/references/analysis-playbook.md +53 -0
- package/skills/platform-apex-logs-debug/references/benchmarking-guide.md +287 -0
- package/skills/platform-apex-logs-debug/references/cli-commands.md +368 -0
- package/skills/platform-apex-logs-debug/references/common-issues.md +68 -0
- package/skills/platform-apex-logs-debug/references/debug-log-reference.md +328 -0
- package/skills/platform-apex-logs-debug/references/log-analysis-tools.md +248 -0
- package/skills/platform-apex-logs-debug/references/scoring-rubric.md +21 -0
- package/skills/platform-apex-test-generate/CREDITS.md +5 -0
- package/skills/platform-apex-test-generate/SKILL.md +201 -0
- package/skills/platform-apex-test-generate/assets/test-class-template.cls +93 -0
- package/skills/platform-apex-test-generate/assets/test-data-factory-template.cls +111 -0
- package/skills/platform-apex-test-generate/references/assertion-patterns.md +108 -0
- package/skills/platform-apex-test-generate/references/async-testing.md +193 -0
- package/skills/platform-apex-test-generate/references/mocking-patterns.md +220 -0
- package/skills/platform-apex-test-generate/references/test-data-factory.md +75 -0
- package/skills/platform-apex-test-run/CREDITS.md +22 -0
- package/skills/platform-apex-test-run/README.md +94 -0
- package/skills/platform-apex-test-run/SKILL.md +157 -0
- package/skills/platform-apex-test-run/assets/basic-test.cls +169 -0
- package/skills/platform-apex-test-run/assets/bulk-test.cls +255 -0
- package/skills/platform-apex-test-run/assets/dml-mock.cls +339 -0
- package/skills/platform-apex-test-run/assets/mock-callout-test.cls +353 -0
- package/skills/platform-apex-test-run/assets/stub-provider-example.cls +364 -0
- package/skills/platform-apex-test-run/assets/test-data-factory.cls +328 -0
- package/skills/platform-apex-test-run/hooks/scripts/parse-test-results.py +364 -0
- package/skills/platform-apex-test-run/references/cli-commands.md +289 -0
- package/skills/platform-apex-test-run/references/mocking-patterns.md +500 -0
- package/skills/platform-apex-test-run/references/performance-optimization.md +283 -0
- package/skills/platform-apex-test-run/references/test-fix-loop.md +49 -0
- package/skills/platform-apex-test-run/references/test-patterns.md +154 -0
- package/skills/platform-apex-test-run/references/testing-best-practices.md +509 -0
- package/skills/platform-custom-application-generate/SKILL.md +211 -0
- package/skills/platform-custom-field-generate/SKILL.md +503 -0
- package/skills/platform-custom-lightning-type-generate/SKILL.md +180 -0
- package/skills/platform-custom-lightning-type-generate/assets/primitive-types-and-constraints.md +41 -0
- package/skills/platform-custom-lightning-type-generate/references/widget-rendition.md +124 -0
- package/skills/platform-custom-object-generate/SKILL.md +240 -0
- package/skills/platform-custom-tab-generate/SKILL.md +156 -0
- package/skills/platform-data-manage/CREDITS.md +5 -0
- package/skills/platform-data-manage/README.md +112 -0
- package/skills/platform-data-manage/SKILL.md +234 -0
- package/skills/platform-data-manage/assets/bulk/bulk-insert-10000.apex +293 -0
- package/skills/platform-data-manage/assets/bulk/bulk-insert-200.apex +208 -0
- package/skills/platform-data-manage/assets/bulk/bulk-insert-500.apex +219 -0
- package/skills/platform-data-manage/assets/bulk/bulk-upsert-external-id.apex +324 -0
- package/skills/platform-data-manage/assets/cleanup/delete-by-created-date.apex +319 -0
- package/skills/platform-data-manage/assets/cleanup/delete-by-name.apex +240 -0
- package/skills/platform-data-manage/assets/cleanup/delete-test-data.apex +311 -0
- package/skills/platform-data-manage/assets/cleanup/rollback-transaction.apex +266 -0
- package/skills/platform-data-manage/assets/csv/account-import.csv +11 -0
- package/skills/platform-data-manage/assets/csv/contact-import.csv +11 -0
- package/skills/platform-data-manage/assets/csv/custom-object-import.csv +11 -0
- package/skills/platform-data-manage/assets/csv/opportunity-import.csv +11 -0
- package/skills/platform-data-manage/assets/factories/account-factory.apex +165 -0
- package/skills/platform-data-manage/assets/factories/case-factory.apex +237 -0
- package/skills/platform-data-manage/assets/factories/contact-factory.apex +168 -0
- package/skills/platform-data-manage/assets/factories/custom-object-factory.apex +260 -0
- package/skills/platform-data-manage/assets/factories/event-factory.apex +275 -0
- package/skills/platform-data-manage/assets/factories/hierarchy-factory.apex +372 -0
- package/skills/platform-data-manage/assets/factories/lead-factory.apex +190 -0
- package/skills/platform-data-manage/assets/factories/opportunity-factory.apex +206 -0
- package/skills/platform-data-manage/assets/factories/task-factory.apex +246 -0
- package/skills/platform-data-manage/assets/factories/user-factory.apex +278 -0
- package/skills/platform-data-manage/assets/json/account-contact-tree.json +130 -0
- package/skills/platform-data-manage/assets/json/account-opportunity-tree.json +110 -0
- package/skills/platform-data-manage/assets/json/full-hierarchy-tree.json +188 -0
- package/skills/platform-data-manage/assets/soql/aggregate.soql +226 -0
- package/skills/platform-data-manage/assets/soql/child-to-parent.soql +162 -0
- package/skills/platform-data-manage/assets/soql/parent-to-child.soql +153 -0
- package/skills/platform-data-manage/assets/soql/polymorphic.soql +198 -0
- package/skills/platform-data-manage/assets/soql/subquery.soql +287 -0
- package/skills/platform-data-manage/references/anonymous-apex-guide.md +98 -0
- package/skills/platform-data-manage/references/bulk-operations-guide.md +94 -0
- package/skills/platform-data-manage/references/bulk-testing-example.md +194 -0
- package/skills/platform-data-manage/references/cleanup-rollback-example.md +322 -0
- package/skills/platform-data-manage/references/cleanup-rollback-guide.md +84 -0
- package/skills/platform-data-manage/references/crud-workflow-example.md +183 -0
- package/skills/platform-data-manage/references/governor-limits-reference.md +74 -0
- package/skills/platform-data-manage/references/orchestration.md +174 -0
- package/skills/platform-data-manage/references/relationship-query-examples.md +249 -0
- package/skills/platform-data-manage/references/sf-cli-data-commands.md +158 -0
- package/skills/platform-data-manage/references/soql-relationship-guide.md +84 -0
- package/skills/platform-data-manage/references/test-data-best-practices.md +104 -0
- package/skills/platform-data-manage/references/test-data-factory-usage.md +290 -0
- package/skills/platform-data-manage/references/test-data-patterns.md +98 -0
- package/skills/platform-data-manage/scripts/soql_validator.py +292 -0
- package/skills/platform-data-manage/scripts/validate_data_operation.py +379 -0
- package/skills/platform-docs-get/README.md +66 -0
- package/skills/platform-docs-get/SKILL.md +208 -0
- package/skills/platform-docs-get/requirements.txt +2 -0
- package/skills/platform-docs-get/scripts/extract_help_salesforce.py +497 -0
- package/skills/platform-docs-get/scripts/extract_salesforce_doc.py +357 -0
- package/skills/platform-docs-get/scripts/runtime_bootstrap.py +58 -0
- package/skills/platform-flexipage-generate/SKILL.md +522 -0
- package/skills/platform-lightning-app-coordinate/SKILL.md +423 -0
- package/skills/platform-list-view-generate/SKILL.md +218 -0
- package/skills/platform-metadata-api-context-get/README.md +79 -0
- package/skills/platform-metadata-api-context-get/SKILL.md +466 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AIApplication.json +37 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AIApplicationConfig.json +53 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AIReplyRecommendationsSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AIScoringModelDefinition.json +87 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AIUsecaseDefinition.json +215 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountInsightsSettings.json +30 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountIntelligenceSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountPlanObjMeasCalcDef.json +86 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountPlanSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountRelationshipShareRule.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountSettings.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountingFieldMapping.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountingModelConfig.json +94 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AccountingSettings.json +53 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActionLinkGroupTemplate.json +118 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActionOverride.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActionPlanTemplate.json +166 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActionableListDefinition.json +114 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActionsSettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActivationPlatform.json +95 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActivationPlatformActvAttr.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActivationPlatformField.json +55 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActivitiesSettings.json +136 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActvPfrmDataConnectorS3.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActvPlatformAdncIdentifier.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ActvPlatformFieldValue.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AddressSettings.json +90 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AdvAccountForecastSet.json +261 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AffinityScoreDefinition.json +74 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AgentPlatformSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AgentforceForDevelopersSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AiAuthoringBundle.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AiEvaluationDefinition.json +153 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AiPluginUtteranceDef.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AllOrNoneHeader.json +17 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnalyticSnapshot.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnalyticsDashboard.json +369 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnalyticsSettings.json +488 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnalyticsVisualization.json +180 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnalyticsWorkspace.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AnimationRule.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexClass.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexComponent.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexEmailNotifications.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexPage.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexSettings.json +96 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexTestSuite.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApexTrigger.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppAnalyticsSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppExperienceSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppFrameworkTemplateBundle.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppMenu.json +10 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppointmentAssignmentPolicy.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AppointmentSchedulingPolicy.json +102 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ApprovalProcess.json +234 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ArticleType.json +81 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ArticleType_CustomField.json +88 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ArticleType_Layout.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AssessmentQuestion.json +117 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AssessmentQuestionSet.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AssignmentRules.json +87 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AssociationEngineSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AsyncResult.json +89 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Audience.json +172 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AuraDefinitionBundle.json +94 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AuthProvider.json +169 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AutoResponseRules.json +79 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/AutomatedContactsSettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BaseSharingRule.json +24 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BatchCalcJobDefinition.json +849 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BatchProcessJobDefinition.json +175 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BillingSettings.json +152 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BlacklistedConsumer.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Bot.json +197 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BotBlock.json +86 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BotSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BotTemplate.json +96 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BotVersion.json +667 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BranchManagementSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BrandingSet.json +146 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BriefcaseDefinition.json +127 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BusinessHoursSettings.json +175 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BusinessProcess.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/BusinessProcessGroup.json +91 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CMSConnectSource.json +197 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CallCenter.json +124 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CallCenterRoutingMap.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CallCoachingMediaProvider.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CallOptions.json +17 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CampaignInfluenceModel.json +59 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CampaignSettings.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CancelDeployResult.json +10 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CareBenefitVerifySettings.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CareLimitType.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CareProviderSearchConfig.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CareRequestConfiguration.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CareSystemFieldMapping.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CaseSettings.json +423 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CaseSubjectParticle.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CatalogedApi.json +97 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CatalogedApiArtifactVersionInfo.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CatalogedApiVersion.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Certificate.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChannelLayout.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChatterAnswersSettings.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChatterEmailsMDSettings.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChatterExtension.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChatterSettings.json +92 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ChoiceList.json +66 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ClaimFinancialSettings.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ClauseCatgConfiguration.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CleanDataService.json +166 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CodeBuilderSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CollectionsDashboardSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CommerceSettings.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CommunitiesSettings.json +116 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Community.json +121 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CommunityTemplateDefinition.json +116 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CommunityThemeDefinition.json +146 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CompactLayout.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CompanySettings.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConnectedApp.json +384 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConnectedAppSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ContentAsset.json +121 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ContentSettings.json +116 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ContentTypeBundle.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ContextDefinition.json +340 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ContractSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConvIntelligenceSignalRule.json +106 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConversationChannelDefinition.json +140 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConversationMessageDefinition.json +380 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConversationMessageDefinitionTranslation.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConversationVendorInfo.json +148 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ConversationalIntelligenceSettings.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CorsWhitelistOrigin.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CriteriaBasedSharingRule.json +206 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CspTrustedSite.json +82 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CurrencySettings.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomAddressFieldSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomApplication.json +453 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomApplicationComponent.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomFeedFilter.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomField.json +392 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomFieldDisplay.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomHelpMenuSection.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomIndex.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomLabels.json +69 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomMetadata.json +90 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomNotificationType.json +94 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomObject.json +313 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomObjectTranslation.json +319 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomPageWebLink.json +121 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomPermission.json +65 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomSite.json +288 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomTab.json +97 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomValue.json +85 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/CustomerDataPlatformSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Dashboard.json +584 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataCategoryGroup.json +81 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataConnector.json +230 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataConnectorIngestApi.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataConnectorS3.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataDotComSettings.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataImportManagementSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataKitObjectDependency.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataKitObjectTemplate.json +59 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataObjectBuildOrgTemplate.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataObjectSearchIndexConf.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataPackageKitDefinition.json +74 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataPackageKitObject.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSource.json +29 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSourceBundleDefinition.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSourceField.json +115 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSourceObject.json +93 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSourceTenant.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataSrcDataModelFieldMap.json +69 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataStreamDefinition.json +105 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataStreamTemplate.json +99 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DataWeaveResource.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DebuggingHeader.json +20 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DecisionMatrixDefinition.json +140 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DecisionTable.json +211 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DecisionTableDatasetLink.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DelegateGroup.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DeleteResult.json +22 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DeployResult.json +253 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DeploymentSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DescribeMetadataResult.json +31 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DescribeValueTypeResult.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DevHubSettings.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DgtAssetMgmtProvider.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DgtAssetMgmtPrvdLghtCpnt.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DigitalExperienceBundle.json +102 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DigitalExperienceBundle_Marketing_Workspace_Bundle_and_Folders.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DigitalExperienceBundle_Site_Workspace_Bundle_and_Folders.json +541 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DigitalExperienceConfig.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DisclosureDefinition.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DisclosureDefinitionVersion.json +78 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DisclosureType.json +53 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DiscoveryAIModel.json +263 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DiscoveryGoal.json +361 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DiscoveryStory.json +98 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Document.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DocumentCategory.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DocumentCategoryDocumentType.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DocumentChecklistSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DocumentGenerationSetting.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DocumentType.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DuplicateRule.json +160 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/DynamicFormsSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EACSettings.json +112 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EclairGeoData.json +73 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EinsteinAISettings.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EinsteinAgentSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EinsteinGptSettings.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailAdministrationSettings.json +104 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailAuthorizationSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailIntegrationSettings.json +92 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailServicesFunction.json +116 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailTemplate.json +116 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmailTemplateSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceBranding.json +78 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceConfig.json +318 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceFieldService.json +73 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceFlowConfig.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceLiveAgent.json +141 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmbeddedServiceMenuSettings.json +165 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EmployeeUserSettings.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EnablementMeasureDefinition.json +139 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EnablementProgramDefinition.json +241 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EnblProgramTaskSubCategory.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EncryptionKeySettings.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EnhancedNotesSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EntitlementProcess.json +147 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EntitlementSettings.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EntitlementTemplate.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Error.json +25 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EscalationRules.json +117 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EventDelivery.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EventRelayConfig.json +55 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EventSettings.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/EventSubscription.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExperienceBundle.json +387 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExperienceBundleSettings.json +25 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExperiencePropertyTypeBundle.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExplainabilityMsgTemplate.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExpressionSetDefinition.json +496 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExpressionSetMessageToken.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExpressionSetObjectAlias.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalAIModel.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalAuthIdentityProvider.json +79 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalClientAppSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalClientApplication.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalCredential.json +94 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalDataConnector.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalDataSource.json +162 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalDataTranObject.json +191 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalDataTransportFieldTemplate.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalDataTransportObjectTemplate.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalServiceRegistration.json +121 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExternalServicesSettings.json +34 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppCanvasSettings.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppConfigurablePolicies.json +75 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppGlobalOauthSettings.json +135 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppMobileConfigurablePolicies.json +34 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppMobileSettings.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppNotificationSettings.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppOauthConfigurablePolicies.json +153 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppOauthSettings.json +120 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppPushConfigurablePolicies.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppPushSettings.json +93 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ExtlClntAppSamlConfigurablePolicies.json +119 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FeatureParameterBoolean.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FeatureParameterDate.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FeatureParameterInteger.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FieldMappingConfig.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FieldRestrictionRule.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FieldServiceSettings.json +226 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FieldSet.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FieldSrcTrgtRelationship.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FileUploadAndDownloadSecuritySettings.json +53 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FilesConnectSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlexiPage.json +355 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Flow.json +2377 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlowCategory.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlowDefinition.json +37 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlowSettings.json +124 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlowTest.json +205 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FlowValueMap.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Folder.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FolderShare.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingFilter.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingFilterCondition.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingObjectListSettings.json +77 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingSettings.json +303 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingSourceDefinition.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingType.json +100 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ForecastingTypeSource.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FuelType.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FuelTypeSustnUom.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FunctionReference.json +31 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/FundraisingConfig.json +86 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GatewayProviderPaymentMethodType.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiFunction.json +171 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPlanner.json +215 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPlannerBundle.json +220 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPlugin.json +87 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPluginInstructionDef.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPromptTemplate.json +183 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GenAiPromptTemplateActv.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GiftEntryGridTemplate.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GlobalPicklist.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GlobalPicklistValue.json +81 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GlobalValueSet.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GlobalValueSetTranslation.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/GoogleAppsSettings.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Group.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/HighVelocitySalesSettings.json +96 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/HistoryRetentionPolicy.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/HomePageComponent.json +66 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/HomePageLayout.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IPAddressRange.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IdeasSettings.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IdentityProviderSettings.json +39 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IdentityVerificationProcDef.json +173 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IdentityVerificationProcDtl.json +136 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IdentityVerificationProcFld.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IframeWhiteListUrlSettings.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InboundCertificate.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InboundNetworkConnection.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IncidentMgmtSettings.json +140 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Index.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesEinsteinFeatureSettings.json +34 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesLoyaltySettings.json +108 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesPricingSettings.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesRatingSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesSettings.json +731 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IndustriesUnifiedInventorySettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InsPlcyLimitConsumptionRule.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InstalledPackage.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IntegArtifactDef.json +10 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/IntegrationProviderDef.json +155 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InterestTaggingSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InternalDataConnector.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InvLatePymntRiskCalcSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InventorySettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InvocableActionExtension.json +84 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/InvocableActionSettings.json +28 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/KeywordList.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/KnowledgeSettings.json +280 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LanguageSettings.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Layout.json +659 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LeadConfigSettings.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LeadConvertSettings.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LearningItemType.json +65 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Letterhead.json +119 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningBolt.json +103 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningComponentBundle.json +109 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningExperienceSettings.json +191 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningExperienceTheme.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningMessageChannel.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningOnboardingConfig.json +62 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LightningTypeBundle.json +88 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ListMetadataQuery.json +10 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ListView.json +86 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveAgentSettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveChatAgentConfig.json +188 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveChatButton.json +188 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveChatDeployment.json +81 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveChatSensitiveDataRule.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LiveMessageSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/LoyaltyProgramSetup.json +297 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MLDataDefinition.json +146 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MLPredictionDefinition.json +67 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MacroSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MailMergeSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ManagedContentType.json +86 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ManagedEventSubscription.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ManagedTopics.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MapAndLocationSettings.json +34 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MarketSegmentDefinition.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MarketingAppExtension.json +139 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MatchingRule.json +69 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MeetingsSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MessagingChannel.json +278 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MetadataWithContent.json +24 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Metadata_Type_Limits.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MfgProgramTemplate.json +88 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MfgServiceConsoleSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MilestoneType.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MktCalcInsightObjectDef.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MktDataTranObject.json +99 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MlDomain.json +136 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MobSecurityCertPinConfig.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MobileApplicationDetail.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MobileSecurityAssignment.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MobileSecurityPolicy.json +75 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MobileSettings.json +121 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ModerationRule.json +99 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MutingPermissionSet.json +33 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MyDomainDiscoverableLogin.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/MyDomainSettings.json +140 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NameSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NamedCredential.json +205 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NamedFilter.json +89 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NavigationMenu.json +101 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Network.json +606 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NetworkBranding.json +117 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NotificationTypeConfig.json +75 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/NotificationsSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OauthCustomScope.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OauthOidcSettings.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OauthTokenExchangeHandler.json +119 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ObjectHierarchyRelationship.json +108 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ObjectLinkingSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ObjectSourceTargetMap.json +85 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OcrSampleDocument.json +158 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OcrTemplate.json +180 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniChannelSettings.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniExtTrackingDef.json +66 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniInteractionAccessConfig.json +90 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniInteractionConfig.json +37 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniScript.json +204 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniSupervisorConfig.json +156 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OmniTrackingGroup.json +77 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OnboardingDataObjectGroup.json +131 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OpportunityInsightsSettings.json +30 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OpportunityScoreSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OpportunitySettings.json +132 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OrchestrationPlanCtxMapping.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OrderManagementSettings.json +52 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OrderSettings.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OrgPreferenceSettings.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OrgSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OutboundNetworkConnection.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/OwnerSharingRule.json +206 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Package.json +19 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PardotEinsteinSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PardotSettings.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ParticipantRole.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PartyDataModelSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PathAssistant.json +74 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PathAssistantSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PaymentGatewayProvider.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PaymentsSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PermissionSet.json +372 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PermissionSetGroup.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PermissionSetLicenseDefinition.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PersonAccountOwnerPowerUser.json +38 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Picklist.json +43 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PicklistSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PipelineInspMetricConfig.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformCachePartition.json +79 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEncryptionSettings.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEventChannel.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEventChannelMember.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEventMigration.json +39 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEventSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PlatformEventSubscriberConfig.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Portal.json +137 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PortalDelegablePermissionSet.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PostTemplate.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PredictionBuilderSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PresenceDeclineReason.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PresenceUserConfig.json +122 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PricingActionParameters.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PricingRecipe.json +117 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PrivacySettings.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProcessFlowMigration.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProductAttributeSet.json +33 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProductSettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Profile.json +492 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProfileActionOverride.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProfilePasswordPolicy.json +80 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProfileSearchLayouts.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ProfileSessionSetting.json +55 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Prompt.json +255 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PublicKeyCertificate.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/PublicKeyCertificateSet.json +65 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Queue.json +123 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/QueueRoutingConfig.json +96 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/QuickAction.json +175 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/QuoteSettings.json +36 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ReadResult.json +16 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RealTimeEventSettings.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecommendationStrategy.json +327 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecordActionDeployment.json +184 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecordAggregationDefinition.json +148 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecordAlertCategory.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecordPageSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RecordType.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RedirectWhitelistUrl.json +26 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ReferencedDashboard.json +55 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RegisteredExternalService.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RelatedRecordAssocCriteria.json +75 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RelationshipGraphDefinition.json +63 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RemoteSiteSetting.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Report.json +715 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ReportType.json +118 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RestrictionRule.json +71 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RetailExecutionSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RetrievalSummaryDefinition.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RetrieveRequest.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RetrieveResult.json +103 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Role.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/RoleOrTerritory.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SalesAgreementSettings.json +180 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SalesWorkQueueSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SamlSsoConfig.json +128 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SandboxSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SaveResult.json +22 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SchedulingObjective.json +66 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SchedulingRule.json +66 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SchemaSettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Scontrol.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SearchCustomization.json +120 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SearchLayouts.json +64 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SearchOrgWideObjectConfig.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SearchSettings.json +155 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SecuritySettings.json +437 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceAISetupDefinition.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceAISetupField.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceChannel.json +123 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceCloudVoiceSettings.json +83 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServicePresenceStatus.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceProcess.json +141 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ServiceSetupAssistantSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SessionHeader.json +17 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharedTo.json +105 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingBaseRule.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingReason.json +34 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingRecalculation.json +29 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingRules.json +186 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingSet.json +78 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SharingSettings.json +92 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SiteDotCom.json +37 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SiteSettings.json +60 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Skill.json +69 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SocialCustomerServiceSettings.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SocialProfileSettings.json +35 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SourceTrackingSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StageAssignment.json +113 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StageDefinition.json +237 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StandardValueSet.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StandardValueSetTranslation.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StaticResource.json +49 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/StreamingAppDataConnector.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SubscriptionManagementSettings.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SurveySettings.json +44 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SustainabilityUom.json +61 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SustnUomConversion.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SvcCatalogCategory.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SvcCatalogFulfillmentFlow.json +99 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SvcCatalogItemDef.json +202 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/SynonymDictionary.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Tag.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TagSet.json +47 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory.json +39 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory2.json +112 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory2Model.json +41 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory2Rule.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory2Settings.json +111 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Territory2Type.json +42 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TimeSheetTemplate.json +75 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TimelineObjectDefinition.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TopicsForObjects.json +38 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TrailheadSettings.json +40 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TransactionSecurityPolicy.json +127 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Translations.json +976 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/TrialOrgSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UIBundle.json +54 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UIObjectRelationConfig.json +101 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UiFormatSpecificationSet.json +103 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UiPreviewMessageTabDef.json +70 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UpsertResult.json +25 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserAccessPolicy.json +120 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserAuthCertificate.json +57 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserCriteria.json +48 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserEngagementSettings.json +136 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserInterfaceSettings.json +96 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserManagementSettings.json +108 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserProfileSearchScope.json +8 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/UserProvisioningConfig.json +72 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/ValidationRule.json +51 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/VirtualVisitConfig.json +97 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/VoiceSettings.json +68 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WarrantyLifeCycleMgmtSettings.json +32 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveAnalyticAssetCollection.json +73 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveApplication.json +56 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveComponent.json +46 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveDashboard.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveDataflow.json +45 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveDataset.json +50 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveLens.json +59 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveRecipe.json +58 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveTemplateBundle.json +37 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WaveXmd.json +567 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WebLink.json +117 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WebStoreBundle.json +10 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WebStoreTemplate.json +166 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WorkDotComSettings.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WorkSkillRouting.json +76 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/Workflow.json +415 -0
- package/skills/platform-metadata-api-context-get/data/metadata_api/WorkforceEngagementSettings.json +56 -0
- package/skills/platform-metadata-api-context-get/examples/README.md +169 -0
- package/skills/platform-metadata-api-context-get/examples/bash_section_loading.sh +142 -0
- package/skills/platform-metadata-api-context-get/examples/javascript_section_loading.js +162 -0
- package/skills/platform-metadata-api-context-get/examples/python_section_loading.py +112 -0
- package/skills/platform-metadata-api-context-get/references/metadata_index_table.md +654 -0
- package/skills/platform-metadata-api-context-get/references/usage_guide.md +420 -0
- package/skills/platform-metadata-deploy/CREDITS.md +25 -0
- package/skills/platform-metadata-deploy/README.md +104 -0
- package/skills/platform-metadata-deploy/SKILL.md +213 -0
- package/skills/platform-metadata-deploy/assets/destructiveChanges.xml +143 -0
- package/skills/platform-metadata-deploy/assets/package.xml +121 -0
- package/skills/platform-metadata-deploy/references/agent-deployment-guide.md +628 -0
- package/skills/platform-metadata-deploy/references/deploy.sh +73 -0
- package/skills/platform-metadata-deploy/references/deployment-report-template.md +89 -0
- package/skills/platform-metadata-deploy/references/deployment-workflows.md +395 -0
- package/skills/platform-metadata-deploy/references/orchestration.md +183 -0
- package/skills/platform-metadata-deploy/references/trigger-deployment-safety.md +376 -0
- package/skills/platform-permission-set-generate/SKILL.md +189 -0
- package/skills/platform-soql-query/CREDITS.md +21 -0
- package/skills/platform-soql-query/README.md +41 -0
- package/skills/platform-soql-query/SKILL.md +142 -0
- package/skills/platform-soql-query/assets/aggregate-queries.soql +242 -0
- package/skills/platform-soql-query/assets/basic-queries.soql +188 -0
- package/skills/platform-soql-query/assets/bulkified-query-pattern.cls +280 -0
- package/skills/platform-soql-query/assets/optimization-patterns.soql +259 -0
- package/skills/platform-soql-query/assets/relationship-queries.soql +203 -0
- package/skills/platform-soql-query/assets/selector-class.cls +219 -0
- package/skills/platform-soql-query/references/anti-patterns.md +348 -0
- package/skills/platform-soql-query/references/cli-commands.md +358 -0
- package/skills/platform-soql-query/references/field-coverage-rules.md +514 -0
- package/skills/platform-soql-query/references/query-optimization.md +142 -0
- package/skills/platform-soql-query/references/selector-patterns.md +479 -0
- package/skills/platform-soql-query/references/soql-reference.md +227 -0
- package/skills/platform-soql-query/references/soql-syntax-reference.md +208 -0
- package/skills/platform-soql-query/scripts/post-tool-validate.py +322 -0
- package/skills/platform-trust-archive-manage/SKILL.md +121 -0
- package/skills/platform-trust-archive-manage/examples/monitor-failed-jobs.md +47 -0
- package/skills/platform-trust-archive-manage/references/archive-activity-entity.md +59 -0
- package/skills/platform-trust-archive-manage/references/connect-api-operations.md +157 -0
- package/skills/platform-validation-rule-generate/SKILL.md +74 -0
- package/skills/recommending-devops-tests/SKILL.md +1 -1
- package/skills/running-devops-test-suite/SKILL.md +1 -1
- package/skills/activating-datacloud/CREDITS.md +0 -5
|
@@ -0,0 +1,3359 @@
|
|
|
1
|
+
"""Phase 2 Batch 1 integration tests for `main.py`.
|
|
2
|
+
|
|
3
|
+
End-to-end pipeline exercise without hitting a real org. Every SOQL-level
|
|
4
|
+
primitive (`fetch_*`, `run_sf`, `probe_channels`) is mocked on the
|
|
5
|
+
`main` module's import namespace so the orchestrator sees synthetic
|
|
6
|
+
rows shaped like live describe output.
|
|
7
|
+
|
|
8
|
+
What these tests assert:
|
|
9
|
+
* RESULT-level behavior — the `.emit_ctx.json` that main.py writes
|
|
10
|
+
is the contract with emit_result.py. We read that JSON back and
|
|
11
|
+
assert status + key counts.
|
|
12
|
+
* Tree shape — `declared_action_tree.json` is parsed; node count,
|
|
13
|
+
depth, kind counts, and the AGENT block are checked against
|
|
14
|
+
fixture expectations.
|
|
15
|
+
* Failure-mode mapping — probe failures map to RETRIEVE_FAILED
|
|
16
|
+
(design decision, see module docstring); empty planner fetch →
|
|
17
|
+
AGENT_NOT_FOUND; empty bot fetch → AGENT_NOT_FOUND + AVAILABLE_BOTS.
|
|
18
|
+
|
|
19
|
+
Every test must run offline. If you see a real `sf` subprocess spawn or
|
|
20
|
+
a real `urllib` request in a failure output, a mock is missing.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
import tempfile
|
|
28
|
+
import unittest
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
from unittest import mock
|
|
31
|
+
|
|
32
|
+
from . import _bootstrap # noqa: F401
|
|
33
|
+
|
|
34
|
+
import config # type: ignore
|
|
35
|
+
import soql_loader # type: ignore
|
|
36
|
+
import main # type: ignore
|
|
37
|
+
from tests.fixtures import genai_payloads as fx # type: ignore
|
|
38
|
+
|
|
39
|
+
# SKILL_ROOT is now file-relative (Path(__file__).resolve().parent.parent in
|
|
40
|
+
# config.py), so config.SOQL_DIR auto-resolves to the repo's assets/soql/
|
|
41
|
+
# under test. No env-var setup is needed.
|
|
42
|
+
# soql_loader still captures SOQL_DIR via `from config import SOQL_DIR` at
|
|
43
|
+
# module top, so we mirror its binding here defensively in case any test
|
|
44
|
+
# imported soql_loader before config's file-relative resolution kicked in.
|
|
45
|
+
_REPO_SOQL_DIR = Path(__file__).resolve().parent.parent.parent / "assets" / "soql"
|
|
46
|
+
soql_loader.SOQL_DIR = _REPO_SOQL_DIR
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _args(work_dir: Path, **overrides) -> list[str]:
|
|
50
|
+
base = [
|
|
51
|
+
"--org-alias", "test-org",
|
|
52
|
+
"--agent", overrides.pop("agent", "MyAgent"),
|
|
53
|
+
"--work-dir", str(work_dir),
|
|
54
|
+
"--parallelism", "2",
|
|
55
|
+
]
|
|
56
|
+
for k, v in overrides.items():
|
|
57
|
+
flag = "--" + k.replace("_", "-")
|
|
58
|
+
if isinstance(v, bool):
|
|
59
|
+
if v:
|
|
60
|
+
base.append(flag)
|
|
61
|
+
else:
|
|
62
|
+
base.extend([flag, str(v)])
|
|
63
|
+
return base
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _mock_wave_a_classic():
|
|
67
|
+
"""Patch every main.fetch_* Wave A function with classic-shape returns."""
|
|
68
|
+
return [
|
|
69
|
+
mock.patch.object(main, "fetch_planner_definition", return_value=fx.CLASSIC_PLANNER),
|
|
70
|
+
mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.CLASSIC_PLUGINS),
|
|
71
|
+
mock.patch.object(main, "fetch_planner_bundle_functions", return_value=fx.CLASSIC_BUNDLE_FN_JOIN),
|
|
72
|
+
mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.CLASSIC_FUNCTIONS),
|
|
73
|
+
mock.patch.object(main, "fetch_plugin_instructions", return_value=fx.CLASSIC_INSTRUCTIONS),
|
|
74
|
+
mock.patch.object(main, "fetch_plugin_functions", return_value=fx.CLASSIC_PLUGIN_FUNCTIONS),
|
|
75
|
+
mock.patch.object(main, "fetch_planner_attrs", return_value=fx.CLASSIC_ATTRS),
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _mock_wave_b_classic():
|
|
80
|
+
return [
|
|
81
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=fx.CLASSIC_APEX_ROWS),
|
|
82
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]),
|
|
83
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=fx.CLASSIC_FLOW_DEFS),
|
|
84
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]),
|
|
85
|
+
mock.patch.object(
|
|
86
|
+
main, "fetch_flow_metadata",
|
|
87
|
+
side_effect=lambda vid, *a, **kw: fx.CLASSIC_FLOW_METADATA.get(vid),
|
|
88
|
+
),
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _mock_wave_a_nga():
|
|
93
|
+
return [
|
|
94
|
+
mock.patch.object(main, "fetch_planner_definition", return_value=fx.NGA_PLANNER),
|
|
95
|
+
mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.NGA_PLUGINS),
|
|
96
|
+
mock.patch.object(main, "fetch_planner_bundle_functions", return_value=[]),
|
|
97
|
+
mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.NGA_FUNCTIONS),
|
|
98
|
+
mock.patch.object(main, "fetch_plugin_instructions", return_value=[]),
|
|
99
|
+
mock.patch.object(main, "fetch_plugin_functions", return_value=fx.NGA_PLUGIN_FUNCTIONS),
|
|
100
|
+
mock.patch.object(main, "fetch_planner_attrs", return_value=[]),
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _mock_wave_b_nga():
|
|
105
|
+
return [
|
|
106
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]),
|
|
107
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=fx.NGA_APEX_BY_ID),
|
|
108
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]),
|
|
109
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=fx.NGA_FLOW_DEF_BY_ID),
|
|
110
|
+
mock.patch.object(main, "fetch_flow_metadata", return_value={
|
|
111
|
+
"Id": "301VF999NGAVER", "FullName": "NGAResolvedFlow-1", "Metadata": {},
|
|
112
|
+
}),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _mock_auth_probe(probe_result=None):
|
|
117
|
+
"""Patch run_sf (for org_display) + probe_channels + bot data fetches."""
|
|
118
|
+
probe_result = probe_result or fx.probe_ok_payload()
|
|
119
|
+
org_display_payload = {
|
|
120
|
+
"status": 0,
|
|
121
|
+
"result": {
|
|
122
|
+
"instanceUrl": "https://example.my.salesforce.com",
|
|
123
|
+
"accessToken": "00Dxx0000000000!AQ_fake_token_value",
|
|
124
|
+
"id": "https://login.salesforce.com/id/00Dxx0000000000AAA/005xx0000000000AAA",
|
|
125
|
+
"apiVersion": "60.0",
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
# The code reads `result.id` — some orgs return a full URL here, some
|
|
129
|
+
# return the 18-char id directly. We patch to a direct 18-char id to
|
|
130
|
+
# keep the derivation trivial.
|
|
131
|
+
org_display_payload["result"]["id"] = "00Dxx0000000000AAA"
|
|
132
|
+
return [
|
|
133
|
+
mock.patch.object(main, "run_sf", return_value=org_display_payload),
|
|
134
|
+
mock.patch.object(main, "probe_channels", return_value=probe_result),
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _mock_bot_resolution(agent_api_name="MyAgent", versions=("v5",), active="v5",
|
|
139
|
+
bot_def=None):
|
|
140
|
+
bot_def = bot_def or fx.BOT_DEFINITION_DETAIL_CLASSIC
|
|
141
|
+
return [
|
|
142
|
+
mock.patch.object(
|
|
143
|
+
main, "fetch_bot_versions",
|
|
144
|
+
return_value=fx.make_bot_versions(agent_api_name, versions, active),
|
|
145
|
+
),
|
|
146
|
+
mock.patch.object(main, "fetch_bot_definition_details", return_value=bot_def),
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _apply_all(patches):
|
|
151
|
+
"""Enter every patch in `patches`; return a list of the started mocks."""
|
|
152
|
+
mocks = []
|
|
153
|
+
for p in patches:
|
|
154
|
+
mocks.append(p.start())
|
|
155
|
+
return mocks
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _read_ctx(work_dir: Path) -> dict:
|
|
159
|
+
return json.loads((work_dir / ".emit_ctx.json").read_text())
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _read_tree(work_dir: Path) -> dict:
|
|
163
|
+
return json.loads((work_dir / "declared_action_tree.json").read_text())
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
# Classic happy path
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class ClassicHappyPathTests(unittest.TestCase):
|
|
172
|
+
def test_classic_pipeline_builds_tree(self):
|
|
173
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
174
|
+
work_dir = Path(tmp) / "work"
|
|
175
|
+
data_root = Path(tmp) / "data"
|
|
176
|
+
cache_root = Path(tmp) / "cache"
|
|
177
|
+
|
|
178
|
+
patches = [
|
|
179
|
+
*_mock_auth_probe(),
|
|
180
|
+
*_mock_bot_resolution(),
|
|
181
|
+
*_mock_wave_a_classic(),
|
|
182
|
+
*_mock_wave_b_classic(),
|
|
183
|
+
# Keep pipeline writes contained to tmp.
|
|
184
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
185
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
186
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
187
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
188
|
+
]
|
|
189
|
+
_apply_all(patches)
|
|
190
|
+
try:
|
|
191
|
+
rc = main.main(_args(work_dir))
|
|
192
|
+
finally:
|
|
193
|
+
for p in patches:
|
|
194
|
+
p.stop()
|
|
195
|
+
|
|
196
|
+
self.assertEqual(rc, 0)
|
|
197
|
+
ctx = _read_ctx(work_dir)
|
|
198
|
+
self.assertIn(ctx["status"], ("OK", "PARTIAL_OK"))
|
|
199
|
+
self.assertEqual(ctx["agent_api_name"], "MyAgent")
|
|
200
|
+
self.assertEqual(ctx["agent_version"], "v5")
|
|
201
|
+
self.assertTrue(ctx["version_auto_picked"])
|
|
202
|
+
|
|
203
|
+
tree = _read_tree(work_dir)
|
|
204
|
+
# 6 topics, no bundle-direct actions (a planner never has direct
|
|
205
|
+
# functions — 2026-05-05). Root has exactly TOPIC children.
|
|
206
|
+
self.assertEqual(len(tree["root"]["children"]), 6)
|
|
207
|
+
# Agent block fields resolved from BotDefinition detail row
|
|
208
|
+
self.assertEqual(tree["agent"]["generation"], "classic")
|
|
209
|
+
self.assertEqual(tree["agent"]["planner_type"],
|
|
210
|
+
"AiCopilot__ReActAiPlannerV1")
|
|
211
|
+
# Kind counts — BOT_DEFINITION, TOPIC(6), GEN_AI_FUNCTION(2 in
|
|
212
|
+
# Topic1, 0 elsewhere).
|
|
213
|
+
counts = tree["_kind_counts"]
|
|
214
|
+
self.assertEqual(counts.get("BOT_DEFINITION"), 1)
|
|
215
|
+
self.assertEqual(counts.get("TOPIC"), 6)
|
|
216
|
+
self.assertEqual(counts.get("GEN_AI_FUNCTION"), 2)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# ---------------------------------------------------------------------------
|
|
220
|
+
# NGA happy path
|
|
221
|
+
# ---------------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class NgaHappyPathTests(unittest.TestCase):
|
|
225
|
+
def test_nga_pipeline_reverse_lookup_builds_tree(self):
|
|
226
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
227
|
+
work_dir = Path(tmp) / "work"
|
|
228
|
+
data_root = Path(tmp) / "data"
|
|
229
|
+
cache_root = Path(tmp) / "cache"
|
|
230
|
+
|
|
231
|
+
patches = [
|
|
232
|
+
*_mock_auth_probe(),
|
|
233
|
+
*_mock_bot_resolution(
|
|
234
|
+
agent_api_name="MyAgent2",
|
|
235
|
+
bot_def=fx.BOT_DEFINITION_DETAIL_NGA,
|
|
236
|
+
),
|
|
237
|
+
*_mock_wave_a_nga(),
|
|
238
|
+
*_mock_wave_b_nga(),
|
|
239
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
240
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
241
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
242
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
243
|
+
]
|
|
244
|
+
_apply_all(patches)
|
|
245
|
+
try:
|
|
246
|
+
rc = main.main(_args(work_dir, agent="MyAgent2"))
|
|
247
|
+
finally:
|
|
248
|
+
for p in patches:
|
|
249
|
+
p.stop()
|
|
250
|
+
|
|
251
|
+
self.assertEqual(rc, 0)
|
|
252
|
+
tree = _read_tree(work_dir)
|
|
253
|
+
self.assertEqual(tree["agent"]["generation"], "nga")
|
|
254
|
+
self.assertEqual(tree["agent"]["planner_type"],
|
|
255
|
+
"Atlas__ConcurrentMultiAgentOrchestration")
|
|
256
|
+
# 1 topic + 0 bundle actions; topic has 2 functions. Confirm
|
|
257
|
+
# both topic-scope functions are present.
|
|
258
|
+
self.assertEqual(tree["_kind_counts"].get("TOPIC"), 1)
|
|
259
|
+
self.assertEqual(tree["_kind_counts"].get("GEN_AI_FUNCTION"), 2)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
# Sequential planner (no plugins)
|
|
264
|
+
# ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class SequentialPlannerTests(unittest.TestCase):
|
|
268
|
+
def test_zero_plugins_one_bundle_function(self):
|
|
269
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
270
|
+
work_dir = Path(tmp) / "work"
|
|
271
|
+
data_root = Path(tmp) / "data"
|
|
272
|
+
cache_root = Path(tmp) / "cache"
|
|
273
|
+
|
|
274
|
+
patches = [
|
|
275
|
+
*_mock_auth_probe(),
|
|
276
|
+
*_mock_bot_resolution(agent_api_name="SequentialAgent"),
|
|
277
|
+
mock.patch.object(main, "fetch_planner_definition",
|
|
278
|
+
return_value=fx.SEQ_PLANNER),
|
|
279
|
+
mock.patch.object(main, "fetch_plugins_by_planner", return_value=[]),
|
|
280
|
+
mock.patch.object(main, "fetch_planner_bundle_functions", return_value=[]),
|
|
281
|
+
mock.patch.object(main, "fetch_functions_by_plugins",
|
|
282
|
+
return_value=fx.SEQ_FUNCTIONS),
|
|
283
|
+
mock.patch.object(main, "fetch_plugin_instructions", return_value=[]),
|
|
284
|
+
mock.patch.object(main, "fetch_plugin_functions", return_value=[]),
|
|
285
|
+
mock.patch.object(main, "fetch_planner_attrs", return_value=[]),
|
|
286
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]),
|
|
287
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]),
|
|
288
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]),
|
|
289
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]),
|
|
290
|
+
mock.patch.object(main, "fetch_flow_metadata", return_value=None),
|
|
291
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
292
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
293
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
294
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
295
|
+
]
|
|
296
|
+
_apply_all(patches)
|
|
297
|
+
try:
|
|
298
|
+
rc = main.main(_args(work_dir, agent="SequentialAgent"))
|
|
299
|
+
finally:
|
|
300
|
+
for p in patches:
|
|
301
|
+
p.stop()
|
|
302
|
+
|
|
303
|
+
self.assertEqual(rc, 0)
|
|
304
|
+
tree = _read_tree(work_dir)
|
|
305
|
+
# 2026-05-05: a planner never has direct functions. A
|
|
306
|
+
# SequentialPlannerIntentClassifier bot with zero plugins
|
|
307
|
+
# therefore has zero declared actions — `functions_by_plugins`
|
|
308
|
+
# short-circuits on empty plugin_ids. The tree is a bare
|
|
309
|
+
# BOT_DEFINITION with no children; no TOPIC, no
|
|
310
|
+
# GEN_AI_FUNCTION, no STANDARD_ACTION.
|
|
311
|
+
counts = tree["_kind_counts"]
|
|
312
|
+
self.assertNotIn("TOPIC", counts)
|
|
313
|
+
self.assertNotIn("GEN_AI_FUNCTION", counts)
|
|
314
|
+
self.assertNotIn("STANDARD_ACTION", counts)
|
|
315
|
+
self.assertEqual(counts.get("BOT_DEFINITION"), 1)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# ---------------------------------------------------------------------------
|
|
319
|
+
# Bot not found
|
|
320
|
+
# ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class BotNotFoundTests(unittest.TestCase):
|
|
324
|
+
def test_empty_bot_versions_emits_agent_not_found(self):
|
|
325
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
326
|
+
work_dir = Path(tmp) / "work"
|
|
327
|
+
|
|
328
|
+
patches = [
|
|
329
|
+
*_mock_auth_probe(),
|
|
330
|
+
mock.patch.object(main, "fetch_bot_versions", return_value=[]),
|
|
331
|
+
]
|
|
332
|
+
_apply_all(patches)
|
|
333
|
+
try:
|
|
334
|
+
rc = main.main(_args(work_dir, agent="MissingAgent"))
|
|
335
|
+
finally:
|
|
336
|
+
for p in patches:
|
|
337
|
+
p.stop()
|
|
338
|
+
|
|
339
|
+
self.assertEqual(rc, 1)
|
|
340
|
+
ctx = _read_ctx(work_dir)
|
|
341
|
+
self.assertEqual(ctx["status"], "AGENT_NOT_FOUND")
|
|
342
|
+
self.assertEqual(ctx["available_bots"], "")
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
# ---------------------------------------------------------------------------
|
|
346
|
+
# Probe failure on mandatory field → RETRIEVE_FAILED + "schema-drift" detail.
|
|
347
|
+
# ---------------------------------------------------------------------------
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class ProbeFailureTests(unittest.TestCase):
|
|
351
|
+
def test_probe_failed_emits_retrieve_failed_schema_drift(self):
|
|
352
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
353
|
+
work_dir = Path(tmp) / "work"
|
|
354
|
+
|
|
355
|
+
patches = _mock_auth_probe(
|
|
356
|
+
probe_result=fx.probe_failed_payload(
|
|
357
|
+
sobject="GenAiPlannerDefinition",
|
|
358
|
+
missing=["PlannerType"],
|
|
359
|
+
),
|
|
360
|
+
)
|
|
361
|
+
_apply_all(patches)
|
|
362
|
+
try:
|
|
363
|
+
rc = main.main(_args(work_dir))
|
|
364
|
+
finally:
|
|
365
|
+
for p in patches:
|
|
366
|
+
p.stop()
|
|
367
|
+
|
|
368
|
+
self.assertEqual(rc, 1)
|
|
369
|
+
ctx = _read_ctx(work_dir)
|
|
370
|
+
self.assertEqual(ctx["status"], "RETRIEVE_FAILED")
|
|
371
|
+
self.assertIn("schema-drift", ctx["error_detail"])
|
|
372
|
+
self.assertIn("PlannerType", ctx["error_detail"])
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# ---------------------------------------------------------------------------
|
|
376
|
+
# Cache hit / force refresh
|
|
377
|
+
# ---------------------------------------------------------------------------
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class CacheBehaviourTests(unittest.TestCase):
|
|
381
|
+
def test_cache_hit_skips_wave_calls(self):
|
|
382
|
+
"""Populate a fresh manifest, confirm pipeline returns CACHE_HIT=true
|
|
383
|
+
without invoking any Wave A fetcher."""
|
|
384
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
385
|
+
work_dir = Path(tmp) / "work"
|
|
386
|
+
data_root = Path(tmp) / "data"
|
|
387
|
+
cache_root = Path(tmp) / "cache"
|
|
388
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
389
|
+
cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
390
|
+
cache_dir.mkdir(parents=True)
|
|
391
|
+
data_dir.mkdir(parents=True)
|
|
392
|
+
tree_base = "MyAgent_v5_metadata_tree"
|
|
393
|
+
(data_dir / f"{tree_base}.json").write_text("{}")
|
|
394
|
+
|
|
395
|
+
import datetime as dt
|
|
396
|
+
from config import SCHEMA_VERSION
|
|
397
|
+
manifest = {
|
|
398
|
+
"built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
399
|
+
"schema_version": SCHEMA_VERSION,
|
|
400
|
+
"agent": {
|
|
401
|
+
"version": "v5", "bot_id": "0Xa000000000ABC",
|
|
402
|
+
"generation": "classic", "_version_auto_picked": True,
|
|
403
|
+
},
|
|
404
|
+
"node_count": 12, "depth": 3, "kind_counts": {},
|
|
405
|
+
"ttl_days": 7,
|
|
406
|
+
"data_path": str(data_dir / f"{tree_base}.json"),
|
|
407
|
+
"partial": False, "unresolved_count": 0,
|
|
408
|
+
}
|
|
409
|
+
(cache_dir / "manifest.json").write_text(json.dumps(manifest))
|
|
410
|
+
|
|
411
|
+
# Wave fetchers get mocks that would raise if touched.
|
|
412
|
+
forbidden = [
|
|
413
|
+
mock.patch.object(main, "fetch_planner_definition",
|
|
414
|
+
side_effect=AssertionError("cache hit MUST NOT run Wave A")),
|
|
415
|
+
]
|
|
416
|
+
|
|
417
|
+
patches = [
|
|
418
|
+
*_mock_auth_probe(),
|
|
419
|
+
*_mock_bot_resolution(),
|
|
420
|
+
*forbidden,
|
|
421
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
422
|
+
side_effect=lambda o, a, v: data_dir),
|
|
423
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
424
|
+
side_effect=lambda o, a, v: cache_dir),
|
|
425
|
+
]
|
|
426
|
+
_apply_all(patches)
|
|
427
|
+
try:
|
|
428
|
+
rc = main.main(_args(work_dir))
|
|
429
|
+
finally:
|
|
430
|
+
for p in patches:
|
|
431
|
+
p.stop()
|
|
432
|
+
|
|
433
|
+
self.assertEqual(rc, 0)
|
|
434
|
+
ctx = _read_ctx(work_dir)
|
|
435
|
+
self.assertEqual(ctx["status"], "OK")
|
|
436
|
+
self.assertTrue(ctx["cache_hit"])
|
|
437
|
+
self.assertEqual(ctx["node_count"], 12)
|
|
438
|
+
|
|
439
|
+
def test_force_refresh_reruns_pipeline_even_if_cache_is_fresh(self):
|
|
440
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
441
|
+
work_dir = Path(tmp) / "work"
|
|
442
|
+
data_root = Path(tmp) / "data"
|
|
443
|
+
cache_root = Path(tmp) / "cache"
|
|
444
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
445
|
+
cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
446
|
+
cache_dir.mkdir(parents=True)
|
|
447
|
+
data_dir.mkdir(parents=True)
|
|
448
|
+
(data_dir / "MyAgent_v5_metadata_tree.json").write_text("{}")
|
|
449
|
+
|
|
450
|
+
import datetime as dt
|
|
451
|
+
from config import SCHEMA_VERSION
|
|
452
|
+
manifest = {
|
|
453
|
+
"built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
454
|
+
"schema_version": SCHEMA_VERSION,
|
|
455
|
+
"agent": {"version": "v5"},
|
|
456
|
+
"node_count": 1, "depth": 1, "kind_counts": {},
|
|
457
|
+
"ttl_days": 7,
|
|
458
|
+
"data_path": str(data_dir / "MyAgent_v5_metadata_tree.json"),
|
|
459
|
+
"partial": False, "unresolved_count": 0,
|
|
460
|
+
}
|
|
461
|
+
(cache_dir / "manifest.json").write_text(json.dumps(manifest))
|
|
462
|
+
|
|
463
|
+
patches = [
|
|
464
|
+
*_mock_auth_probe(),
|
|
465
|
+
*_mock_bot_resolution(),
|
|
466
|
+
*_mock_wave_a_classic(),
|
|
467
|
+
*_mock_wave_b_classic(),
|
|
468
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
469
|
+
side_effect=lambda o, a, v: data_dir),
|
|
470
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
471
|
+
side_effect=lambda o, a, v: cache_dir),
|
|
472
|
+
]
|
|
473
|
+
_apply_all(patches)
|
|
474
|
+
try:
|
|
475
|
+
rc = main.main(_args(work_dir, force=True))
|
|
476
|
+
planner_mock = main.fetch_planner_definition # the MagicMock
|
|
477
|
+
finally:
|
|
478
|
+
for p in patches:
|
|
479
|
+
p.stop()
|
|
480
|
+
|
|
481
|
+
self.assertEqual(rc, 0)
|
|
482
|
+
# Wave A ran — the planner mock was called exactly once.
|
|
483
|
+
self.assertEqual(planner_mock.call_count, 1)
|
|
484
|
+
ctx = _read_ctx(work_dir)
|
|
485
|
+
self.assertFalse(ctx["cache_hit"])
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
# ---------------------------------------------------------------------------
|
|
489
|
+
# 401 refresh path
|
|
490
|
+
# ---------------------------------------------------------------------------
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class Refresh401Tests(unittest.TestCase):
|
|
494
|
+
def test_401_on_tooling_query_triggers_refresh_and_completes(self):
|
|
495
|
+
"""Patch `fetch_soql.tooling_query` so the REAL fetch_planner_definition
|
|
496
|
+
runs; the first query raises HTTPError 401, refresh fires, the retry
|
|
497
|
+
succeeds.
|
|
498
|
+
|
|
499
|
+
This exercises the production retry_on_401 path end-to-end .
|
|
500
|
+
We drive retries at the `tooling_query` layer — the fetcher wrappers
|
|
501
|
+
in fetch_soql are untouched. If the refresh contract regressed, this
|
|
502
|
+
test would either 401 a second time (if stale creds were reused) or
|
|
503
|
+
propagate the original HTTPError (if the decorator didn't catch).
|
|
504
|
+
"""
|
|
505
|
+
import fetch_soql # type: ignore
|
|
506
|
+
|
|
507
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
508
|
+
work_dir = Path(tmp) / "work"
|
|
509
|
+
data_root = Path(tmp) / "data"
|
|
510
|
+
cache_root = Path(tmp) / "cache"
|
|
511
|
+
|
|
512
|
+
# Stub the raw tooling_query primitive: first call for the
|
|
513
|
+
# planner raises 401; subsequent calls (after refresh) return
|
|
514
|
+
# the classic planner row.
|
|
515
|
+
call_counter = {"n": 0}
|
|
516
|
+
refresh_counter = {"n": 0}
|
|
517
|
+
|
|
518
|
+
def tooling_query_401_once(creds_provider, soql, *, api_version, on_401_refresh):
|
|
519
|
+
call_counter["n"] += 1
|
|
520
|
+
# Call creds_provider + refresh to simulate retry_on_401's
|
|
521
|
+
# behavior. The real tooling_query wires retry_on_401
|
|
522
|
+
# INSIDE itself; here we emulate the same contract so the
|
|
523
|
+
# refresh counter advances and the planner row is returned.
|
|
524
|
+
creds_provider()
|
|
525
|
+
if call_counter["n"] == 1:
|
|
526
|
+
# Simulate the wrapped call having already handled the
|
|
527
|
+
# 401 (called refresh_fn + retried) and then returned
|
|
528
|
+
# the row. We invoke on_401_refresh ourselves to prove
|
|
529
|
+
# the refresh plumbing is callable from the fetcher.
|
|
530
|
+
on_401_refresh()
|
|
531
|
+
refresh_counter["n"] += 1
|
|
532
|
+
# Shape the response — fetch_planner_definition extracts
|
|
533
|
+
# records[0]. For non-planner queries (A2..A7) this same
|
|
534
|
+
# stub returns an empty records list and those fetchers
|
|
535
|
+
# short-circuit gracefully.
|
|
536
|
+
if "GenAiPlannerDefinition" in soql:
|
|
537
|
+
return {"records": [fx.CLASSIC_PLANNER]}
|
|
538
|
+
if "GenAiPluginDefinition" in soql and "WHERE PlannerId" in soql:
|
|
539
|
+
return {"records": fx.CLASSIC_PLUGINS}
|
|
540
|
+
if "GenAiPlannerFunctionDef" in soql:
|
|
541
|
+
return {"records": fx.CLASSIC_BUNDLE_FN_JOIN}
|
|
542
|
+
if "GenAiFunctionDefinition" in soql:
|
|
543
|
+
return {"records": fx.CLASSIC_FUNCTIONS}
|
|
544
|
+
if "GenAiPluginInstructionDef" in soql:
|
|
545
|
+
return {"records": fx.CLASSIC_INSTRUCTIONS}
|
|
546
|
+
if "GenAiPluginFunctionDef" in soql:
|
|
547
|
+
return {"records": fx.CLASSIC_PLUGIN_FUNCTIONS}
|
|
548
|
+
if "GenAiPlannerAttrDefinition" in soql:
|
|
549
|
+
return {"records": fx.CLASSIC_ATTRS}
|
|
550
|
+
if "ApexClass" in soql:
|
|
551
|
+
return {"records": fx.CLASSIC_APEX_ROWS}
|
|
552
|
+
if "FlowDefinition" in soql:
|
|
553
|
+
return {"records": fx.CLASSIC_FLOW_DEFS}
|
|
554
|
+
if "FROM Flow " in soql or "FROM Flow\n" in soql:
|
|
555
|
+
return {"records": []}
|
|
556
|
+
return {"records": []}
|
|
557
|
+
|
|
558
|
+
patches = [
|
|
559
|
+
*_mock_auth_probe(),
|
|
560
|
+
*_mock_bot_resolution(),
|
|
561
|
+
mock.patch.object(fetch_soql, "tooling_query",
|
|
562
|
+
side_effect=tooling_query_401_once),
|
|
563
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
564
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
565
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
566
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
567
|
+
]
|
|
568
|
+
_apply_all(patches)
|
|
569
|
+
try:
|
|
570
|
+
rc = main.main(_args(work_dir))
|
|
571
|
+
finally:
|
|
572
|
+
for p in patches:
|
|
573
|
+
p.stop()
|
|
574
|
+
|
|
575
|
+
self.assertEqual(rc, 0)
|
|
576
|
+
# Refresh plumbing was invoked at least once.
|
|
577
|
+
self.assertGreaterEqual(refresh_counter["n"], 1)
|
|
578
|
+
ctx = _read_ctx(work_dir)
|
|
579
|
+
self.assertIn(ctx["status"], ("OK", "PARTIAL_OK"))
|
|
580
|
+
# No token ever leaks into the ctx (redact_error contract).
|
|
581
|
+
self.assertNotIn("Bearer", json.dumps(ctx))
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
# ---------------------------------------------------------------------------
|
|
585
|
+
# Wave-A layer-2/3 task failures — must surface in `_unresolved` (PARTIAL_OK),
|
|
586
|
+
# not silently drop. Mirrors Wave-B's `wave-b-batch-failed` shape.
|
|
587
|
+
# ---------------------------------------------------------------------------
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
class WaveAUnresolvedTests(unittest.TestCase):
|
|
591
|
+
def test_wave_a_layer3_failure_lands_in_unresolved_and_partial_ok(self):
|
|
592
|
+
from rest_client import RestClientError # type: ignore
|
|
593
|
+
|
|
594
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
595
|
+
work_dir = Path(tmp) / "work"
|
|
596
|
+
data_root = Path(tmp) / "data"
|
|
597
|
+
cache_root = Path(tmp) / "cache"
|
|
598
|
+
|
|
599
|
+
# Force the A6 channel (plugin_functions) to fail with a
|
|
600
|
+
# transient 5xx-shaped RestClientError. The other Wave-A
|
|
601
|
+
# channels (plugins, bundle_functions, functions, instructions)
|
|
602
|
+
# still resolve cleanly so the bundle parse still produces
|
|
603
|
+
# topics. This must NOT abort the pipeline; the failure has
|
|
604
|
+
# to land in `_unresolved` with a `wave-a-plugin-functions-failed:`
|
|
605
|
+
# reason and the run must finish PARTIAL_OK.
|
|
606
|
+
failing_exc = RestClientError("transient 5xx")
|
|
607
|
+
|
|
608
|
+
patches = [
|
|
609
|
+
*_mock_auth_probe(),
|
|
610
|
+
*_mock_bot_resolution(),
|
|
611
|
+
mock.patch.object(main, "fetch_planner_definition",
|
|
612
|
+
return_value=fx.CLASSIC_PLANNER),
|
|
613
|
+
mock.patch.object(main, "fetch_plugins_by_planner",
|
|
614
|
+
return_value=fx.CLASSIC_PLUGINS),
|
|
615
|
+
mock.patch.object(main, "fetch_planner_bundle_functions",
|
|
616
|
+
return_value=fx.CLASSIC_BUNDLE_FN_JOIN),
|
|
617
|
+
mock.patch.object(main, "fetch_functions_by_plugins",
|
|
618
|
+
return_value=fx.CLASSIC_FUNCTIONS),
|
|
619
|
+
mock.patch.object(main, "fetch_plugin_instructions",
|
|
620
|
+
return_value=fx.CLASSIC_INSTRUCTIONS),
|
|
621
|
+
mock.patch.object(main, "fetch_plugin_functions",
|
|
622
|
+
side_effect=failing_exc),
|
|
623
|
+
mock.patch.object(main, "fetch_planner_attrs",
|
|
624
|
+
return_value=fx.CLASSIC_ATTRS),
|
|
625
|
+
*_mock_wave_b_classic(),
|
|
626
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
627
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
628
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
629
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
630
|
+
]
|
|
631
|
+
_apply_all(patches)
|
|
632
|
+
try:
|
|
633
|
+
rc = main.main(_args(work_dir))
|
|
634
|
+
finally:
|
|
635
|
+
for p in patches:
|
|
636
|
+
p.stop()
|
|
637
|
+
|
|
638
|
+
self.assertEqual(rc, 0)
|
|
639
|
+
ctx = _read_ctx(work_dir)
|
|
640
|
+
# The post-finalize tree (final swap target) is the contract
|
|
641
|
+
# surface for downstream readers; declared_action_tree.json
|
|
642
|
+
# in work_dir is the pre-finalize snapshot.
|
|
643
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
644
|
+
final_tree = json.loads(
|
|
645
|
+
(data_dir / "MyAgent_v5_metadata_tree.json").read_text()
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# (b) The failed channel surfaces in tree["_unresolved"] with
|
|
649
|
+
# reason `wave-a-plugin-functions-failed:<redacted>`. Same
|
|
650
|
+
# shape as `wave-b-batch-failed` entries.
|
|
651
|
+
unresolved = final_tree.get("_unresolved") or []
|
|
652
|
+
wave_a_entries = [
|
|
653
|
+
u for u in unresolved
|
|
654
|
+
if u.get("reason", "").startswith("wave-a-plugin-functions-failed:")
|
|
655
|
+
]
|
|
656
|
+
self.assertEqual(
|
|
657
|
+
len(wave_a_entries), 1,
|
|
658
|
+
f"expected exactly one wave-a-plugin-functions-failed entry; got {unresolved!r}",
|
|
659
|
+
)
|
|
660
|
+
self.assertEqual(wave_a_entries[0]["channel"], "plugin-functions")
|
|
661
|
+
# Redacted message preserved enough signal to debug.
|
|
662
|
+
self.assertIn("transient 5xx", wave_a_entries[0]["reason"])
|
|
663
|
+
|
|
664
|
+
# (a) Other Wave-A channels still produced their data — topics
|
|
665
|
+
# and agent metadata land in the tree. plugin_functions
|
|
666
|
+
# populates the plugin → function join, so its absence
|
|
667
|
+
# means topics can't list per-function actions, but
|
|
668
|
+
# plugins-as-topics still appear.
|
|
669
|
+
self.assertEqual(final_tree["agent"]["api_name"], "MyAgent")
|
|
670
|
+
self.assertEqual(final_tree["agent"]["generation"], "classic")
|
|
671
|
+
kinds = [c["kind"] for c in final_tree["root"]["children"]]
|
|
672
|
+
self.assertIn("TOPIC", kinds,
|
|
673
|
+
"topics from surviving Wave-A channels should still land")
|
|
674
|
+
|
|
675
|
+
# (c) tree's _partial reflects the failure (finalize promotes
|
|
676
|
+
# based on _unresolved count even when pending is empty).
|
|
677
|
+
# Mirrors the Wave-B contract.
|
|
678
|
+
self.assertTrue(final_tree["_partial"])
|
|
679
|
+
|
|
680
|
+
# (d) downstream STATUS is PARTIAL_OK — never a silent OK.
|
|
681
|
+
self.assertEqual(ctx["status"], "PARTIAL_OK")
|
|
682
|
+
|
|
683
|
+
def test_wave_a_clean_run_has_no_wave_a_unresolved_entries(self):
|
|
684
|
+
# Negative control — when every Wave-A channel succeeds, there
|
|
685
|
+
# must be NO `wave-a-*-failed` entries in tree["_unresolved"].
|
|
686
|
+
# Guards against a writer that always appends.
|
|
687
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
688
|
+
work_dir = Path(tmp) / "work"
|
|
689
|
+
data_root = Path(tmp) / "data"
|
|
690
|
+
cache_root = Path(tmp) / "cache"
|
|
691
|
+
|
|
692
|
+
patches = [
|
|
693
|
+
*_mock_auth_probe(),
|
|
694
|
+
*_mock_bot_resolution(),
|
|
695
|
+
*_mock_wave_a_classic(),
|
|
696
|
+
*_mock_wave_b_classic(),
|
|
697
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
698
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
699
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
700
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
701
|
+
]
|
|
702
|
+
_apply_all(patches)
|
|
703
|
+
try:
|
|
704
|
+
rc = main.main(_args(work_dir))
|
|
705
|
+
finally:
|
|
706
|
+
for p in patches:
|
|
707
|
+
p.stop()
|
|
708
|
+
|
|
709
|
+
self.assertEqual(rc, 0)
|
|
710
|
+
tree = _read_tree(work_dir)
|
|
711
|
+
for u in (tree.get("_unresolved") or []):
|
|
712
|
+
reason = u.get("reason", "")
|
|
713
|
+
self.assertFalse(
|
|
714
|
+
reason.startswith("wave-a-") and reason.endswith("-failed:"),
|
|
715
|
+
f"unexpected wave-a entry on a clean run: {u!r}",
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
# ---------------------------------------------------------------------------
|
|
720
|
+
# Smoke: empty args raise argparse error — guard against a test infra
|
|
721
|
+
# regression where CLI parsing silently accepts partial argv.
|
|
722
|
+
# ---------------------------------------------------------------------------
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
class PartialTreeTests(unittest.TestCase):
|
|
726
|
+
"""When parse_wave returns a _partial tree (max-depth cap or residual
|
|
727
|
+
pending refs), main.py must surface STATUS=PARTIAL_OK with the
|
|
728
|
+
`_partial_reason` + `pending_fetches_count` plumbed through."""
|
|
729
|
+
|
|
730
|
+
def test_max_depth_cap_surfaces_partial_ok(self):
|
|
731
|
+
import parse_wave # type: ignore
|
|
732
|
+
|
|
733
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
734
|
+
work_dir = Path(tmp) / "work"
|
|
735
|
+
data_root = Path(tmp) / "data"
|
|
736
|
+
cache_root = Path(tmp) / "cache"
|
|
737
|
+
|
|
738
|
+
# Wrap walk_and_inflate so it injects a synthetic
|
|
739
|
+
# depth-cap-pending ref regardless of flow_children contents.
|
|
740
|
+
# This mirrors what a real deep-subflow traversal would
|
|
741
|
+
# accumulate when MAX_BFS_DEPTH trips.
|
|
742
|
+
original_walk = parse_wave.walk_and_inflate
|
|
743
|
+
|
|
744
|
+
def walk_with_fake_depth_cap(node, flow_children, depth=0, pending_out=None):
|
|
745
|
+
if pending_out is not None:
|
|
746
|
+
pending_out.setdefault("FLOW", set()).add("DeeplyNestedSubflow")
|
|
747
|
+
return original_walk(node, flow_children, depth, pending_out)
|
|
748
|
+
|
|
749
|
+
patches = [
|
|
750
|
+
*_mock_auth_probe(),
|
|
751
|
+
*_mock_bot_resolution(),
|
|
752
|
+
*_mock_wave_a_classic(),
|
|
753
|
+
*_mock_wave_b_classic(),
|
|
754
|
+
mock.patch.object(parse_wave, "walk_and_inflate",
|
|
755
|
+
side_effect=walk_with_fake_depth_cap),
|
|
756
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
757
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
758
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
759
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
760
|
+
]
|
|
761
|
+
_apply_all(patches)
|
|
762
|
+
try:
|
|
763
|
+
rc = main.main(_args(work_dir))
|
|
764
|
+
finally:
|
|
765
|
+
for p in patches:
|
|
766
|
+
p.stop()
|
|
767
|
+
|
|
768
|
+
self.assertEqual(rc, 0)
|
|
769
|
+
ctx = _read_ctx(work_dir)
|
|
770
|
+
# Partial flag may emit as OK (finalize's _partial recompute
|
|
771
|
+
# depends on pending + planner_ok), so we check the tree's
|
|
772
|
+
# internal signal rather than the ctx status alone.
|
|
773
|
+
tree = _read_tree(work_dir)
|
|
774
|
+
self.assertEqual(tree["_partial_reason"], "max-depth-cap")
|
|
775
|
+
self.assertIn("DeeplyNestedSubflow", tree["_pending_fetches"]["FLOW"])
|
|
776
|
+
self.assertGreaterEqual(ctx["pending_fetches_count"], 1)
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
class RenderFailureIntegrationTests(unittest.TestCase):
|
|
780
|
+
"""end-to-end — render raises -> sidecar + RESULT signals.
|
|
781
|
+
|
|
782
|
+
The defect both reviewers flagged: if render_architecture raises,
|
|
783
|
+
_run_finalize writes `architecture.md.error` and continues. The
|
|
784
|
+
tree JSON + summary land fine; STATUS stays OK. Consumers have no
|
|
785
|
+
way to know the headline output is missing.
|
|
786
|
+
|
|
787
|
+
This test drives the full pipeline with a patched renderer that
|
|
788
|
+
raises, then asserts:
|
|
789
|
+
* The sidecar landed in the data_dir.
|
|
790
|
+
* The emit ctx carries render_failed=True + a detail string.
|
|
791
|
+
* _emit_ok auto-promoted STATUS to PARTIAL_OK.
|
|
792
|
+
* emit_result (run as a subprocess against the ctx) emits
|
|
793
|
+
RENDER_FAILED=true in the RESULT block.
|
|
794
|
+
"""
|
|
795
|
+
|
|
796
|
+
def test_render_raises_surfaces_partial_ok_and_render_failed_true(self):
|
|
797
|
+
import render_architecture # type: ignore
|
|
798
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
799
|
+
work_dir = Path(tmp) / "work"
|
|
800
|
+
data_root = Path(tmp) / "data"
|
|
801
|
+
cache_root = Path(tmp) / "cache"
|
|
802
|
+
|
|
803
|
+
def _boom(*_a, **_kw):
|
|
804
|
+
raise RuntimeError("render exploded for test")
|
|
805
|
+
|
|
806
|
+
patches = [
|
|
807
|
+
*_mock_auth_probe(),
|
|
808
|
+
*_mock_bot_resolution(),
|
|
809
|
+
*_mock_wave_a_classic(),
|
|
810
|
+
*_mock_wave_b_classic(),
|
|
811
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
812
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
813
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
814
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
815
|
+
# Patch the renderer at its import site. `main._run_finalize`
|
|
816
|
+
# does a lazy `from render_architecture import render`, so
|
|
817
|
+
# we patch `render_architecture.render` module-wide.
|
|
818
|
+
mock.patch.object(render_architecture, "render",
|
|
819
|
+
side_effect=_boom),
|
|
820
|
+
]
|
|
821
|
+
_apply_all(patches)
|
|
822
|
+
try:
|
|
823
|
+
rc = main.main(_args(work_dir))
|
|
824
|
+
finally:
|
|
825
|
+
for p in patches:
|
|
826
|
+
p.stop()
|
|
827
|
+
|
|
828
|
+
self.assertEqual(rc, 0)
|
|
829
|
+
|
|
830
|
+
# Sidecar landed in the final data_dir (post-swap).
|
|
831
|
+
# filenames are self-identifying.
|
|
832
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
833
|
+
sidecar = data_dir / "MyAgent_v5_architecture.md.error"
|
|
834
|
+
self.assertTrue(sidecar.is_file(), f"sidecar missing at {sidecar}")
|
|
835
|
+
self.assertIn(
|
|
836
|
+
"render exploded for test",
|
|
837
|
+
sidecar.read_text(),
|
|
838
|
+
)
|
|
839
|
+
# architecture.md must NOT have been produced.
|
|
840
|
+
self.assertFalse((data_dir / "MyAgent_v5_architecture.md").is_file())
|
|
841
|
+
|
|
842
|
+
# emit ctx carries the render-failure signals.
|
|
843
|
+
ctx = _read_ctx(work_dir)
|
|
844
|
+
self.assertTrue(ctx["render_failed"])
|
|
845
|
+
self.assertIn("RuntimeError", ctx["render_error_detail"])
|
|
846
|
+
self.assertEqual(ctx["architecture_path"], "")
|
|
847
|
+
# _emit_ok path leaves status=OK when tree is healthy; the
|
|
848
|
+
# emit_result-time auto-promote is what flips it to PARTIAL_OK.
|
|
849
|
+
# But the tree IS healthy here, so status stays OK at the ctx
|
|
850
|
+
# level — the promotion happens in build_block.
|
|
851
|
+
self.assertIn(ctx["status"], ("OK", "PARTIAL_OK"))
|
|
852
|
+
|
|
853
|
+
# Drive emit_result against this ctx and confirm the RESULT
|
|
854
|
+
# block reflects the render failure.
|
|
855
|
+
tools_dir = Path(__file__).resolve().parent.parent.parent / "tools"
|
|
856
|
+
import subprocess, sys as _sys
|
|
857
|
+
env = {**os.environ, "WORK_DIR": str(work_dir)}
|
|
858
|
+
r = subprocess.run(
|
|
859
|
+
[_sys.executable, str(tools_dir / "emit_result.py")],
|
|
860
|
+
env=env, capture_output=True, text=True, timeout=30,
|
|
861
|
+
)
|
|
862
|
+
self.assertEqual(r.returncode, 0, msg=r.stderr)
|
|
863
|
+
block = r.stdout
|
|
864
|
+
self.assertIn("STATUS=PARTIAL_OK", block)
|
|
865
|
+
self.assertIn("RENDER_FAILED=true", block)
|
|
866
|
+
self.assertIn("RENDER_ERROR_DETAIL=", block)
|
|
867
|
+
self.assertIn("OUTPUT_ARCHITECTURE_PATH=", block)
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
class ArgParseSmokeTests(unittest.TestCase):
|
|
871
|
+
def test_missing_required_args_raises_systemexit(self):
|
|
872
|
+
# argparse prints usage to stderr before SystemExit. Redirect so
|
|
873
|
+
# the test runner output stays clean.
|
|
874
|
+
import contextlib
|
|
875
|
+
import io
|
|
876
|
+
with self.assertRaises(SystemExit), contextlib.redirect_stderr(io.StringIO()):
|
|
877
|
+
main.parse_args([])
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
# ---------------------------------------------------------------------------
|
|
881
|
+
# thread-safe refresh_fn with monotonic dedupe window
|
|
882
|
+
# ---------------------------------------------------------------------------
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
class ThreadSafeRefreshTests(unittest.TestCase):
|
|
886
|
+
"""`_build_creds_plumbing` must:
|
|
887
|
+
* serialize concurrent refresh_fn calls behind a lock (no overlapping
|
|
888
|
+
`sf org display` spawns)
|
|
889
|
+
* dedupe refreshes within a monotonic time window — N threads racing
|
|
890
|
+
within the window collapse to a single `resolve_creds` call
|
|
891
|
+
|
|
892
|
+
These are pre-conditions for Wave B's parallelism: if 5 parallel
|
|
893
|
+
Flow.Metadata fetches each 401 simultaneously, only ONE real sf-CLI
|
|
894
|
+
spawn should fire (not 5).
|
|
895
|
+
"""
|
|
896
|
+
|
|
897
|
+
def _spawn_workers(self, refresh_fn, n=5, barrier=None):
|
|
898
|
+
"""Run `n` threads that each call refresh_fn once. Returns the
|
|
899
|
+
list of return values. A `threading.Barrier` is used to align the
|
|
900
|
+
thread launches — all threads hit `refresh_fn` within the same
|
|
901
|
+
monotonic window, which is the condition the dedupe optimizes for.
|
|
902
|
+
"""
|
|
903
|
+
import threading as _t
|
|
904
|
+
results: list = [None] * n
|
|
905
|
+
threads: list[_t.Thread] = []
|
|
906
|
+
|
|
907
|
+
def _worker(i):
|
|
908
|
+
if barrier is not None:
|
|
909
|
+
barrier.wait()
|
|
910
|
+
results[i] = refresh_fn()
|
|
911
|
+
|
|
912
|
+
for i in range(n):
|
|
913
|
+
threads.append(_t.Thread(target=_worker, args=(i,)))
|
|
914
|
+
for t in threads:
|
|
915
|
+
t.start()
|
|
916
|
+
for t in threads:
|
|
917
|
+
t.join()
|
|
918
|
+
return results
|
|
919
|
+
|
|
920
|
+
def test_five_threads_single_refresh_within_window(self):
|
|
921
|
+
"""5 threads concurrently call refresh_fn within the 1-second
|
|
922
|
+
dedupe window → `resolve_creds` is invoked exactly ONCE.
|
|
923
|
+
"""
|
|
924
|
+
import threading as _t
|
|
925
|
+
|
|
926
|
+
call_count = {"n": 0}
|
|
927
|
+
call_lock = _t.Lock()
|
|
928
|
+
|
|
929
|
+
def fake_resolve():
|
|
930
|
+
# Increment under a lock so a second concurrent call couldn't
|
|
931
|
+
# race and register as one (this is what we're testing AGAINST:
|
|
932
|
+
# the outer dedupe should guarantee only one entry here).
|
|
933
|
+
with call_lock:
|
|
934
|
+
call_count["n"] += 1
|
|
935
|
+
return ("https://example.my.salesforce.com", "tok_v2")
|
|
936
|
+
|
|
937
|
+
_provider, refresh, _cell = main._build_creds_plumbing(
|
|
938
|
+
("https://example.my.salesforce.com", "tok_v1"),
|
|
939
|
+
resolve_creds=fake_resolve,
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
barrier = _t.Barrier(5)
|
|
943
|
+
results = self._spawn_workers(refresh, n=5, barrier=barrier)
|
|
944
|
+
|
|
945
|
+
# Dedupe held — exactly ONE real resolve spawn.
|
|
946
|
+
self.assertEqual(call_count["n"], 1)
|
|
947
|
+
# Every thread got the refreshed tuple back.
|
|
948
|
+
self.assertTrue(all(r == ("https://example.my.salesforce.com", "tok_v2") for r in results))
|
|
949
|
+
|
|
950
|
+
def test_refresh_lock_serializes_resolve_spawns(self):
|
|
951
|
+
"""If 5 threads race with a SHORT dedupe window (simulated via
|
|
952
|
+
a 0-length window), `resolve_creds` calls are serialized by the
|
|
953
|
+
lock — we observe a strict 1:1 count of entries to spawns. This
|
|
954
|
+
is the "last-writer-wins" worst case: every thread still spawns
|
|
955
|
+
once, but they're serialized, NOT overlapping. The test asserts
|
|
956
|
+
the lock DOES serialize (not that it dedupes) when the window
|
|
957
|
+
is effectively disabled.
|
|
958
|
+
"""
|
|
959
|
+
import threading as _t
|
|
960
|
+
|
|
961
|
+
active = {"n": 0, "max": 0}
|
|
962
|
+
spawns = {"n": 0}
|
|
963
|
+
state_lock = _t.Lock()
|
|
964
|
+
|
|
965
|
+
def fake_resolve():
|
|
966
|
+
with state_lock:
|
|
967
|
+
active["n"] += 1
|
|
968
|
+
active["max"] = max(active["max"], active["n"])
|
|
969
|
+
spawns["n"] += 1
|
|
970
|
+
# Hold for a short beat to let any racing worker enter if the
|
|
971
|
+
# lock weren't serializing.
|
|
972
|
+
import time as _time
|
|
973
|
+
_time.sleep(0.02)
|
|
974
|
+
with state_lock:
|
|
975
|
+
active["n"] -= 1
|
|
976
|
+
return ("url", "tok")
|
|
977
|
+
|
|
978
|
+
_provider, refresh, _cell = main._build_creds_plumbing(
|
|
979
|
+
("url", "old"),
|
|
980
|
+
resolve_creds=fake_resolve,
|
|
981
|
+
dedupe_window_s=0.0, # disable dedupe so every call spawns
|
|
982
|
+
)
|
|
983
|
+
|
|
984
|
+
self._spawn_workers(refresh, n=5)
|
|
985
|
+
|
|
986
|
+
# Lock serialized the spawns — no overlap inside `fake_resolve`.
|
|
987
|
+
self.assertEqual(active["max"], 1)
|
|
988
|
+
# All 5 eventually ran (no silent drops when dedupe is off).
|
|
989
|
+
self.assertEqual(spawns["n"], 5)
|
|
990
|
+
|
|
991
|
+
def test_sequential_calls_outside_window_trigger_new_refresh(self):
|
|
992
|
+
"""A refresh OUTSIDE the dedupe window is NOT suppressed. The
|
|
993
|
+
dedupe is a ceiling, not a one-shot latch.
|
|
994
|
+
"""
|
|
995
|
+
import time as _time
|
|
996
|
+
|
|
997
|
+
call_count = {"n": 0}
|
|
998
|
+
|
|
999
|
+
def fake_resolve():
|
|
1000
|
+
call_count["n"] += 1
|
|
1001
|
+
return ("url", f"tok_{call_count['n']}")
|
|
1002
|
+
|
|
1003
|
+
_provider, refresh, _cell = main._build_creds_plumbing(
|
|
1004
|
+
("url", "tok_0"),
|
|
1005
|
+
resolve_creds=fake_resolve,
|
|
1006
|
+
dedupe_window_s=0.05, # 50ms window for test latency
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
refresh()
|
|
1010
|
+
_time.sleep(0.08) # sleep past the window
|
|
1011
|
+
refresh()
|
|
1012
|
+
|
|
1013
|
+
self.assertEqual(call_count["n"], 2)
|
|
1014
|
+
|
|
1015
|
+
def test_provider_reads_cell_after_refresh(self):
|
|
1016
|
+
"""After refresh mutates the cell, the NEXT `creds_provider()`
|
|
1017
|
+
call returns the fresh tuple (the contract).
|
|
1018
|
+
"""
|
|
1019
|
+
provider, refresh, cell = main._build_creds_plumbing(
|
|
1020
|
+
("url", "old"),
|
|
1021
|
+
resolve_creds=lambda: ("url", "new"),
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
self.assertEqual(provider(), ("url", "old"))
|
|
1025
|
+
refresh()
|
|
1026
|
+
self.assertEqual(provider(), ("url", "new"))
|
|
1027
|
+
self.assertEqual(cell[0], ("url", "new"))
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
# ---------------------------------------------------------------------------
|
|
1031
|
+
# on_401_refresh is a required kwarg on every fetcher
|
|
1032
|
+
# ---------------------------------------------------------------------------
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
class RequiredOn401RefreshKwargTests(unittest.TestCase):
|
|
1036
|
+
"""Every fetcher in `fetch_soql` must make `on_401_refresh` a REQUIRED
|
|
1037
|
+
keyword-only argument. The previous default (`on_401_refresh or
|
|
1038
|
+
creds_provider`) silently collapsed to "re-read the same stale token"
|
|
1039
|
+
when a caller passed `None` — the retry hit the same stale token on
|
|
1040
|
+
the second attempt and 401'd again, bypassing entirely.
|
|
1041
|
+
|
|
1042
|
+
We can't exercise the full retry chain here (that's Fix 5's
|
|
1043
|
+
integration test) — this test enforces the call-site contract at the
|
|
1044
|
+
signature level, so a regression is a TypeError not an auth bypass.
|
|
1045
|
+
"""
|
|
1046
|
+
|
|
1047
|
+
FETCHERS = (
|
|
1048
|
+
"fetch_planner_definition",
|
|
1049
|
+
"fetch_plugins_by_planner",
|
|
1050
|
+
"fetch_planner_bundle_functions",
|
|
1051
|
+
"fetch_functions_by_plugins",
|
|
1052
|
+
"fetch_plugin_instructions",
|
|
1053
|
+
"fetch_plugin_functions",
|
|
1054
|
+
"fetch_planner_attrs",
|
|
1055
|
+
"fetch_apex_bodies_by_names",
|
|
1056
|
+
"fetch_apex_bodies_by_ids",
|
|
1057
|
+
"fetch_flow_definition_ids_by_names",
|
|
1058
|
+
"fetch_flow_definition_view_by_durable_ids",
|
|
1059
|
+
"fetch_flow_definition_by_ids",
|
|
1060
|
+
"fetch_flow_metadata",
|
|
1061
|
+
"fetch_bot_versions",
|
|
1062
|
+
"fetch_bot_definition_details",
|
|
1063
|
+
)
|
|
1064
|
+
|
|
1065
|
+
def test_every_fetcher_requires_on_401_refresh(self):
|
|
1066
|
+
"""Each fetcher raises TypeError when `on_401_refresh` is omitted.
|
|
1067
|
+
|
|
1068
|
+
`api_version` is now also required. To
|
|
1069
|
+
isolate the `on_401_refresh` contract (not conflate it with the
|
|
1070
|
+
new `api_version` contract — that's covered by
|
|
1071
|
+
`ApiVersionRequiredOnEveryFetcherTests` below), we pass a valid
|
|
1072
|
+
`api_version` and check the TypeError is specifically about the
|
|
1073
|
+
missing `on_401_refresh` — otherwise a regression that made
|
|
1074
|
+
`on_401_refresh` optional again would be masked by the
|
|
1075
|
+
`api_version` TypeError.
|
|
1076
|
+
"""
|
|
1077
|
+
import fetch_soql # type: ignore
|
|
1078
|
+
|
|
1079
|
+
# Sentinel that won't survive the call — we never reach the HTTP
|
|
1080
|
+
# layer because signature validation fires first.
|
|
1081
|
+
def _noop_provider():
|
|
1082
|
+
return ("url", "tok")
|
|
1083
|
+
|
|
1084
|
+
for name in self.FETCHERS:
|
|
1085
|
+
fn = getattr(fetch_soql, name)
|
|
1086
|
+
with self.subTest(fetcher=name):
|
|
1087
|
+
if name == "fetch_planner_definition":
|
|
1088
|
+
# Signature: (agent_api_name, version, creds_provider, *, ...)
|
|
1089
|
+
args = ("Agent", "v2", _noop_provider)
|
|
1090
|
+
elif name in {
|
|
1091
|
+
"fetch_plugins_by_planner",
|
|
1092
|
+
"fetch_planner_bundle_functions",
|
|
1093
|
+
"fetch_bot_versions", "fetch_bot_definition_details",
|
|
1094
|
+
}:
|
|
1095
|
+
args = ("Name", _noop_provider)
|
|
1096
|
+
elif name in {"fetch_functions_by_plugins",
|
|
1097
|
+
"fetch_plugin_instructions", "fetch_plugin_functions",
|
|
1098
|
+
"fetch_planner_attrs",
|
|
1099
|
+
"fetch_apex_bodies_by_names",
|
|
1100
|
+
"fetch_apex_bodies_by_ids",
|
|
1101
|
+
"fetch_flow_definition_ids_by_names",
|
|
1102
|
+
"fetch_flow_definition_view_by_durable_ids",
|
|
1103
|
+
"fetch_flow_definition_by_ids"}:
|
|
1104
|
+
args = (["Name"], _noop_provider)
|
|
1105
|
+
elif name == "fetch_flow_metadata":
|
|
1106
|
+
args = ("301VF000000xyz", _noop_provider)
|
|
1107
|
+
else:
|
|
1108
|
+
self.fail(f"unmapped fetcher {name}")
|
|
1109
|
+
|
|
1110
|
+
with self.assertRaises(TypeError) as ctx:
|
|
1111
|
+
# Pass api_version so the TypeError pinpoints
|
|
1112
|
+
# on_401_refresh specifically.
|
|
1113
|
+
fn(*args, api_version="v60.0")
|
|
1114
|
+
self.assertIn(
|
|
1115
|
+
"on_401_refresh", str(ctx.exception),
|
|
1116
|
+
msg=f"{name} must name on_401_refresh in its TypeError",
|
|
1117
|
+
)
|
|
1118
|
+
|
|
1119
|
+
def test_every_fetcher_requires_api_version(self):
|
|
1120
|
+
"""every fetcher must require the
|
|
1121
|
+
`api_version` kwarg. Symmetric to the `on_401_refresh` contract.
|
|
1122
|
+
|
|
1123
|
+
Omitting `api_version` must be a TypeError at call time, not a
|
|
1124
|
+
silent regression back to the old hardcoded `v60.0` floor.
|
|
1125
|
+
"""
|
|
1126
|
+
import fetch_soql # type: ignore
|
|
1127
|
+
|
|
1128
|
+
def _noop_provider():
|
|
1129
|
+
return ("url", "tok")
|
|
1130
|
+
|
|
1131
|
+
def _noop_refresh():
|
|
1132
|
+
return ("url", "tok")
|
|
1133
|
+
|
|
1134
|
+
for name in self.FETCHERS:
|
|
1135
|
+
fn = getattr(fetch_soql, name)
|
|
1136
|
+
with self.subTest(fetcher=name):
|
|
1137
|
+
if name == "fetch_planner_definition":
|
|
1138
|
+
args = ("Agent", "v2", _noop_provider)
|
|
1139
|
+
elif name in {
|
|
1140
|
+
"fetch_plugins_by_planner",
|
|
1141
|
+
"fetch_planner_bundle_functions",
|
|
1142
|
+
"fetch_bot_versions", "fetch_bot_definition_details",
|
|
1143
|
+
}:
|
|
1144
|
+
args = ("Name", _noop_provider)
|
|
1145
|
+
elif name in {"fetch_functions_by_plugins",
|
|
1146
|
+
"fetch_plugin_instructions", "fetch_plugin_functions",
|
|
1147
|
+
"fetch_planner_attrs",
|
|
1148
|
+
"fetch_apex_bodies_by_names",
|
|
1149
|
+
"fetch_apex_bodies_by_ids",
|
|
1150
|
+
"fetch_flow_definition_ids_by_names",
|
|
1151
|
+
"fetch_flow_definition_view_by_durable_ids",
|
|
1152
|
+
"fetch_flow_definition_by_ids"}:
|
|
1153
|
+
args = (["Name"], _noop_provider)
|
|
1154
|
+
elif name == "fetch_flow_metadata":
|
|
1155
|
+
args = ("301VF000000xyz", _noop_provider)
|
|
1156
|
+
else:
|
|
1157
|
+
self.fail(f"unmapped fetcher {name}")
|
|
1158
|
+
|
|
1159
|
+
with self.assertRaises(TypeError) as ctx:
|
|
1160
|
+
# Pass on_401_refresh so the TypeError pinpoints
|
|
1161
|
+
# api_version specifically.
|
|
1162
|
+
fn(*args, on_401_refresh=_noop_refresh)
|
|
1163
|
+
self.assertIn(
|
|
1164
|
+
"api_version", str(ctx.exception),
|
|
1165
|
+
msg=f"{name} must name api_version in its TypeError",
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
def test_fetcher_with_explicit_refresh_does_not_raise_typeerror(self):
|
|
1169
|
+
"""Control: passing `on_401_refresh=<callable>` + `api_version=...`
|
|
1170
|
+
bypasses the signature guard and the call reaches inner logic
|
|
1171
|
+
(mocked here). Any non-TypeError outcome is acceptable — we're
|
|
1172
|
+
only asserting the signature is satisfied.
|
|
1173
|
+
|
|
1174
|
+
`api_version` is now a sibling required
|
|
1175
|
+
kwarg to `on_401_refresh`; both must be supplied.
|
|
1176
|
+
"""
|
|
1177
|
+
import fetch_soql # type: ignore
|
|
1178
|
+
|
|
1179
|
+
# Empty-list short-circuit → returns [] without firing a SOQL call.
|
|
1180
|
+
out = fetch_soql.fetch_plugin_instructions(
|
|
1181
|
+
[],
|
|
1182
|
+
lambda: ("url", "tok"),
|
|
1183
|
+
api_version="v60.0",
|
|
1184
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
1185
|
+
)
|
|
1186
|
+
self.assertEqual(out, [])
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
# ---------------------------------------------------------------------------
|
|
1190
|
+
# atomic finalize via staging-sibling swap
|
|
1191
|
+
# ---------------------------------------------------------------------------
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
class AtomicFinalizeTests(unittest.TestCase):
|
|
1195
|
+
"""`_run_finalize` must never leave `data_dir` in an empty / missing
|
|
1196
|
+
state. The prior `shutil.rmtree; rename` pattern opened a window
|
|
1197
|
+
where a crash or a concurrent reader saw an empty path. The new
|
|
1198
|
+
`_swap_dir_atomic` uses staging-siblings + `os.replace` so:
|
|
1199
|
+
* on success, `data_dir` transitions atomically from OLD → NEW
|
|
1200
|
+
* on a mid-swap crash, the backup sibling is restored to `data_dir`
|
|
1201
|
+
"""
|
|
1202
|
+
|
|
1203
|
+
def _make_tree(self) -> dict:
|
|
1204
|
+
return {
|
|
1205
|
+
"_schema_version": "3.0",
|
|
1206
|
+
"agent": {"api_name": "A", "version": "v1"},
|
|
1207
|
+
"root": {"kind": "BOT_DEFINITION", "api_name": "A", "children": []},
|
|
1208
|
+
"node_count": 1, "depth": 0,
|
|
1209
|
+
"_kind_counts": {"BOT_DEFINITION": 1},
|
|
1210
|
+
"_pending_fetches": {k: [] for k in ("FLOW", "APEX", "PROMPT_TEMPLATE", "STANDARD_ACTION")},
|
|
1211
|
+
"_unresolved": [],
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
def test_happy_path_swaps_atomically(self):
|
|
1215
|
+
"""Finalize runs cleanly: data_dir + cache_dir end up populated
|
|
1216
|
+
with the fresh tree/manifest, staging/backup siblings are gone.
|
|
1217
|
+
"""
|
|
1218
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1219
|
+
tmp_p = Path(tmp)
|
|
1220
|
+
work_dir = tmp_p / "work"
|
|
1221
|
+
work_dir.mkdir()
|
|
1222
|
+
data_dir = tmp_p / "data" / "A__v1"
|
|
1223
|
+
cache_dir = tmp_p / "cache" / "A__v1"
|
|
1224
|
+
|
|
1225
|
+
tree = self._make_tree()
|
|
1226
|
+
main._run_finalize(
|
|
1227
|
+
data_dir, cache_dir, tree, work_dir,
|
|
1228
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
1229
|
+
)
|
|
1230
|
+
|
|
1231
|
+
self.assertTrue(data_dir.is_dir())
|
|
1232
|
+
self.assertTrue((data_dir / "A_v1_metadata_tree.json").is_file())
|
|
1233
|
+
self.assertTrue((cache_dir / "manifest.json").is_file())
|
|
1234
|
+
|
|
1235
|
+
# No staging / backup siblings left behind.
|
|
1236
|
+
siblings = list(data_dir.parent.iterdir()) + list(cache_dir.parent.iterdir())
|
|
1237
|
+
for s in siblings:
|
|
1238
|
+
self.assertFalse(
|
|
1239
|
+
s.name.startswith(".") and ("staging" in s.name or "backup" in s.name),
|
|
1240
|
+
f"leftover staging/backup: {s}",
|
|
1241
|
+
)
|
|
1242
|
+
|
|
1243
|
+
def test_existing_dir_replaced_not_emptied_midswap(self):
|
|
1244
|
+
"""Run finalize TWICE. The second run must swap atomically — at
|
|
1245
|
+
no observable moment does `data_dir` exist and contain zero
|
|
1246
|
+
files. We verify by inspecting post-run state (the swap is
|
|
1247
|
+
atomic, so the invariant reduces to "data_dir is populated with
|
|
1248
|
+
NEW artifacts after the call returns").
|
|
1249
|
+
"""
|
|
1250
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1251
|
+
tmp_p = Path(tmp)
|
|
1252
|
+
work_dir = tmp_p / "work"
|
|
1253
|
+
work_dir.mkdir()
|
|
1254
|
+
data_dir = tmp_p / "data" / "A__v1"
|
|
1255
|
+
cache_dir = tmp_p / "cache" / "A__v1"
|
|
1256
|
+
|
|
1257
|
+
# First run
|
|
1258
|
+
main._run_finalize(
|
|
1259
|
+
data_dir, cache_dir, self._make_tree(), work_dir,
|
|
1260
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
1261
|
+
)
|
|
1262
|
+
self.assertTrue((data_dir / "A_v1_metadata_tree.json").is_file())
|
|
1263
|
+
|
|
1264
|
+
# Second run — different node_count so we can confirm the
|
|
1265
|
+
# replacement took effect (not a stale file).
|
|
1266
|
+
tree2 = self._make_tree()
|
|
1267
|
+
tree2["node_count"] = 42
|
|
1268
|
+
main._run_finalize(
|
|
1269
|
+
data_dir, cache_dir, tree2, work_dir,
|
|
1270
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
1271
|
+
)
|
|
1272
|
+
tree_out = json.loads((data_dir / "A_v1_metadata_tree.json").read_text())
|
|
1273
|
+
self.assertEqual(tree_out["node_count"], 42)
|
|
1274
|
+
|
|
1275
|
+
def test_crash_during_final_swap_restores_original(self):
|
|
1276
|
+
"""Inject an `os.replace` failure on the SECOND rename of the
|
|
1277
|
+
data_dir swap (staging → target). The function must:
|
|
1278
|
+
* raise the underlying OSError (we assert)
|
|
1279
|
+
* leave `data_dir` populated with the ORIGINAL contents
|
|
1280
|
+
(backup was restored)
|
|
1281
|
+
|
|
1282
|
+
We patch `main._swap_dir_atomic` internals via patching
|
|
1283
|
+
`os.replace` at the main-module's namespace with a side_effect
|
|
1284
|
+
that fails the second-target replace only.
|
|
1285
|
+
"""
|
|
1286
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1287
|
+
tmp_p = Path(tmp)
|
|
1288
|
+
work_dir = tmp_p / "work"
|
|
1289
|
+
work_dir.mkdir()
|
|
1290
|
+
data_dir = tmp_p / "data" / "A__v1"
|
|
1291
|
+
cache_dir = tmp_p / "cache" / "A__v1"
|
|
1292
|
+
|
|
1293
|
+
# Prime data_dir with sentinel content to prove it survives.
|
|
1294
|
+
data_dir.mkdir(parents=True)
|
|
1295
|
+
(data_dir / "sentinel.txt").write_text("original-data")
|
|
1296
|
+
|
|
1297
|
+
real_replace = os.replace
|
|
1298
|
+
call_seq = {"n": 0}
|
|
1299
|
+
|
|
1300
|
+
def fail_on_staging_to_target(src, dst):
|
|
1301
|
+
"""First replace: target → backup (must succeed, allows
|
|
1302
|
+
the function to proceed to the risky step). Second
|
|
1303
|
+
replace: staging → target (we force this to fail). The
|
|
1304
|
+
function should catch that, restore backup → target, and
|
|
1305
|
+
reraise."""
|
|
1306
|
+
call_seq["n"] += 1
|
|
1307
|
+
# Let the "target → backup" rename succeed (n==1).
|
|
1308
|
+
# Also let the recovery "backup → target" rename succeed
|
|
1309
|
+
# (fires AFTER we raise below). Fail only on n==2 (the
|
|
1310
|
+
# "staging → target" rename).
|
|
1311
|
+
if call_seq["n"] == 2:
|
|
1312
|
+
raise OSError("synthetic swap failure")
|
|
1313
|
+
return real_replace(src, dst)
|
|
1314
|
+
|
|
1315
|
+
with mock.patch.object(main.os, "replace", side_effect=fail_on_staging_to_target):
|
|
1316
|
+
with self.assertRaises(OSError):
|
|
1317
|
+
main._run_finalize(
|
|
1318
|
+
data_dir, cache_dir, self._make_tree(), work_dir,
|
|
1319
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
1320
|
+
)
|
|
1321
|
+
|
|
1322
|
+
# Invariant: data_dir still exists AND still contains the
|
|
1323
|
+
# original sentinel (the backup was restored).
|
|
1324
|
+
self.assertTrue(data_dir.is_dir())
|
|
1325
|
+
self.assertTrue((data_dir / "sentinel.txt").is_file())
|
|
1326
|
+
self.assertEqual((data_dir / "sentinel.txt").read_text(), "original-data")
|
|
1327
|
+
|
|
1328
|
+
def test_leftover_staging_from_prior_crash_is_cleared(self):
|
|
1329
|
+
"""If a previous crashed run left a `.<name>.staging.<pid>`
|
|
1330
|
+
sibling behind, the next finalize blows it away before staging
|
|
1331
|
+
its own writes. Otherwise `mkdir(parents=True)` would raise
|
|
1332
|
+
FileExistsError.
|
|
1333
|
+
"""
|
|
1334
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1335
|
+
tmp_p = Path(tmp)
|
|
1336
|
+
work_dir = tmp_p / "work"
|
|
1337
|
+
work_dir.mkdir()
|
|
1338
|
+
data_dir = tmp_p / "data" / "A__v1"
|
|
1339
|
+
cache_dir = tmp_p / "cache" / "A__v1"
|
|
1340
|
+
|
|
1341
|
+
# Synthesize a leftover staging dir for THIS pid.
|
|
1342
|
+
stale_staging = data_dir.parent / f".{data_dir.name}.staging.{os.getpid()}"
|
|
1343
|
+
stale_staging.mkdir(parents=True)
|
|
1344
|
+
(stale_staging / "stale.txt").write_text("junk")
|
|
1345
|
+
|
|
1346
|
+
main._run_finalize(
|
|
1347
|
+
data_dir, cache_dir, self._make_tree(), work_dir,
|
|
1348
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
1349
|
+
)
|
|
1350
|
+
|
|
1351
|
+
# Stale staging is gone (replaced with a successful swap).
|
|
1352
|
+
self.assertFalse(stale_staging.exists())
|
|
1353
|
+
# And data_dir has the fresh tree.
|
|
1354
|
+
self.assertTrue((data_dir / "A_v1_metadata_tree.json").is_file())
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
# ---------------------------------------------------------------------------
|
|
1358
|
+
# real 401 retry carries the new token
|
|
1359
|
+
# ---------------------------------------------------------------------------
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
class Real401RetryIntegrationTests(unittest.TestCase):
|
|
1363
|
+
"""The existing `Refresh401Tests` mocks at the `tooling_query`
|
|
1364
|
+
boundary — it bypasses the decorator stack and can't verify the
|
|
1365
|
+
retry actually carries the NEW token into the second request.
|
|
1366
|
+
|
|
1367
|
+
This test mocks at the lowest-level `build_opener` seam in
|
|
1368
|
+
`rest_client`. A mock `OpenerDirector.open` inspects the
|
|
1369
|
+
Authorization header on each call:
|
|
1370
|
+
* call 1: Bearer old_token → raise HTTPError(401)
|
|
1371
|
+
* refresh_fn fires (via the real retry_on_401 decorator)
|
|
1372
|
+
* call 2: Bearer new_token → return a valid response
|
|
1373
|
+
|
|
1374
|
+
If the contract regressed — e.g. the retry re-used the stale
|
|
1375
|
+
token — call 2 would still carry Bearer old_token and the test
|
|
1376
|
+
would fail.
|
|
1377
|
+
"""
|
|
1378
|
+
|
|
1379
|
+
def test_retry_carries_new_token_after_401(self):
|
|
1380
|
+
import io
|
|
1381
|
+
import urllib.error
|
|
1382
|
+
import fetch_soql # type: ignore
|
|
1383
|
+
import rest_client # type: ignore
|
|
1384
|
+
|
|
1385
|
+
observed_auth_headers: list[str] = []
|
|
1386
|
+
|
|
1387
|
+
def _make_401_response() -> urllib.error.HTTPError:
|
|
1388
|
+
# HTTPError tolerates hdrs=None; retry_on_401 does not touch
|
|
1389
|
+
# .headers on a 401 (only the 403-path reads .read()).
|
|
1390
|
+
return urllib.error.HTTPError(
|
|
1391
|
+
url="https://example.my.salesforce.com/services/data/v60.0/tooling/query/",
|
|
1392
|
+
code=401,
|
|
1393
|
+
msg="Unauthorized",
|
|
1394
|
+
hdrs=None,
|
|
1395
|
+
fp=io.BytesIO(b"INVALID_SESSION_ID"),
|
|
1396
|
+
)
|
|
1397
|
+
|
|
1398
|
+
class _FakeResp:
|
|
1399
|
+
"""Context-manager compatible fake response returning JSON."""
|
|
1400
|
+
|
|
1401
|
+
def __init__(self, body_bytes: bytes):
|
|
1402
|
+
self._body = body_bytes
|
|
1403
|
+
|
|
1404
|
+
def __enter__(self):
|
|
1405
|
+
return self
|
|
1406
|
+
|
|
1407
|
+
def __exit__(self, *a):
|
|
1408
|
+
return False
|
|
1409
|
+
|
|
1410
|
+
def read(self):
|
|
1411
|
+
return self._body
|
|
1412
|
+
|
|
1413
|
+
class _RecordingOpener:
|
|
1414
|
+
def __init__(self):
|
|
1415
|
+
self.n = 0
|
|
1416
|
+
|
|
1417
|
+
def open(self, req):
|
|
1418
|
+
# Record the Authorization header so the test can assert
|
|
1419
|
+
# the new token landed on the retry request.
|
|
1420
|
+
auth = req.headers.get("Authorization") or req.get_header("Authorization")
|
|
1421
|
+
observed_auth_headers.append(auth or "")
|
|
1422
|
+
self.n += 1
|
|
1423
|
+
if self.n == 1:
|
|
1424
|
+
raise _make_401_response()
|
|
1425
|
+
# Retry: return a valid Tooling query response.
|
|
1426
|
+
return _FakeResp(b'{"records":[{"Id":"001","DeveloperName":"X"}]}')
|
|
1427
|
+
|
|
1428
|
+
# Build creds plumbing that swaps tokens on refresh.
|
|
1429
|
+
provider, refresh, _cell = main._build_creds_plumbing(
|
|
1430
|
+
("https://example.my.salesforce.com", "old_token"),
|
|
1431
|
+
resolve_creds=lambda: ("https://example.my.salesforce.com", "new_token"),
|
|
1432
|
+
dedupe_window_s=0.0, # allow the refresh to fire unconditionally
|
|
1433
|
+
)
|
|
1434
|
+
|
|
1435
|
+
opener = _RecordingOpener()
|
|
1436
|
+
with mock.patch.object(rest_client, "build_opener", return_value=opener):
|
|
1437
|
+
# Use a fetcher that triggers one Tooling query. v2+ branch
|
|
1438
|
+
# goes through `load_soql` + the chain template — exercises the
|
|
1439
|
+
# same tooling_query seam the test is here to verify.
|
|
1440
|
+
result = fetch_soql.fetch_planner_definition(
|
|
1441
|
+
"SomePlanner", "v2", provider,
|
|
1442
|
+
api_version="v60.0", on_401_refresh=refresh,
|
|
1443
|
+
)
|
|
1444
|
+
|
|
1445
|
+
# Contract: both requests were made; first with old_token,
|
|
1446
|
+
# second with new_token (the post-refresh value).
|
|
1447
|
+
self.assertEqual(len(observed_auth_headers), 2)
|
|
1448
|
+
self.assertEqual(observed_auth_headers[0], "Bearer old_token")
|
|
1449
|
+
self.assertEqual(observed_auth_headers[1], "Bearer new_token")
|
|
1450
|
+
# And the retry response shaped correctly.
|
|
1451
|
+
self.assertEqual(result.get("DeveloperName"), "X")
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
class ApiVersionEndToEndTests(unittest.TestCase):
|
|
1455
|
+
"""the `api_version` reported by `sf org display --json`
|
|
1456
|
+
threads through the pipeline all the way to the REST query URL.
|
|
1457
|
+
|
|
1458
|
+
Orgs on v66 must NOT hit `/services/data/v60.0/...` — that was
|
|
1459
|
+
. This test drives the full pipeline with a mocked
|
|
1460
|
+
org-display payload reporting `apiVersion=66.0` and asserts every
|
|
1461
|
+
Tooling/Data query fetcher receives `api_version="v66.0"`.
|
|
1462
|
+
"""
|
|
1463
|
+
|
|
1464
|
+
def test_full_pipeline_passes_v66_to_every_fetcher(self):
|
|
1465
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1466
|
+
work_dir = Path(tmp) / "work"
|
|
1467
|
+
data_root = Path(tmp) / "data"
|
|
1468
|
+
cache_root = Path(tmp) / "cache"
|
|
1469
|
+
|
|
1470
|
+
# sf org display payload reports v66 — this is the shape real
|
|
1471
|
+
# orgs return today (my-org-alias, my-perf-org-alias).
|
|
1472
|
+
org_display_payload = {
|
|
1473
|
+
"status": 0,
|
|
1474
|
+
"result": {
|
|
1475
|
+
"instanceUrl": "https://example.my.salesforce.com",
|
|
1476
|
+
"accessToken": "00Dxx0000000000!AQ_fake_token_value",
|
|
1477
|
+
"id": "00Dxx0000000000AAA",
|
|
1478
|
+
"apiVersion": "66.0",
|
|
1479
|
+
},
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
# Capture api_version passed to each fetcher via mock.call_args.
|
|
1483
|
+
wave_a_patches = [
|
|
1484
|
+
mock.patch.object(main, "fetch_planner_definition",
|
|
1485
|
+
return_value=fx.CLASSIC_PLANNER),
|
|
1486
|
+
mock.patch.object(main, "fetch_plugins_by_planner",
|
|
1487
|
+
return_value=fx.CLASSIC_PLUGINS),
|
|
1488
|
+
mock.patch.object(main, "fetch_planner_bundle_functions",
|
|
1489
|
+
return_value=fx.CLASSIC_BUNDLE_FN_JOIN),
|
|
1490
|
+
mock.patch.object(main, "fetch_functions_by_plugins",
|
|
1491
|
+
return_value=fx.CLASSIC_FUNCTIONS),
|
|
1492
|
+
mock.patch.object(main, "fetch_plugin_instructions",
|
|
1493
|
+
return_value=fx.CLASSIC_INSTRUCTIONS),
|
|
1494
|
+
mock.patch.object(main, "fetch_plugin_functions",
|
|
1495
|
+
return_value=fx.CLASSIC_PLUGIN_FUNCTIONS),
|
|
1496
|
+
mock.patch.object(main, "fetch_planner_attrs",
|
|
1497
|
+
return_value=fx.CLASSIC_ATTRS),
|
|
1498
|
+
]
|
|
1499
|
+
wave_b_patches = [
|
|
1500
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names",
|
|
1501
|
+
return_value=fx.CLASSIC_APEX_ROWS),
|
|
1502
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids",
|
|
1503
|
+
return_value=[]),
|
|
1504
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names",
|
|
1505
|
+
return_value=fx.CLASSIC_FLOW_DEFS),
|
|
1506
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids",
|
|
1507
|
+
return_value=[]),
|
|
1508
|
+
mock.patch.object(
|
|
1509
|
+
main, "fetch_flow_metadata",
|
|
1510
|
+
side_effect=lambda vid, *a, **kw: fx.CLASSIC_FLOW_METADATA.get(vid),
|
|
1511
|
+
),
|
|
1512
|
+
]
|
|
1513
|
+
patches = [
|
|
1514
|
+
mock.patch.object(main, "run_sf", return_value=org_display_payload),
|
|
1515
|
+
mock.patch.object(main, "probe_channels",
|
|
1516
|
+
return_value=fx.probe_ok_payload()),
|
|
1517
|
+
*_mock_bot_resolution(),
|
|
1518
|
+
*wave_a_patches,
|
|
1519
|
+
*wave_b_patches,
|
|
1520
|
+
mock.patch.object(main, "build_agent_data_dir",
|
|
1521
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}"),
|
|
1522
|
+
mock.patch.object(main, "build_agent_cache_dir",
|
|
1523
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}"),
|
|
1524
|
+
]
|
|
1525
|
+
_apply_all(patches)
|
|
1526
|
+
try:
|
|
1527
|
+
rc = main.main(_args(work_dir))
|
|
1528
|
+
# Snapshot call lists BEFORE `p.stop()` restores the
|
|
1529
|
+
# originals — otherwise `main.fetch_*` drops back to the
|
|
1530
|
+
# real function with no `.call_args_list`.
|
|
1531
|
+
fetcher_call_lists = {
|
|
1532
|
+
name: getattr(main, name).call_args_list
|
|
1533
|
+
for name in (
|
|
1534
|
+
"fetch_planner_definition",
|
|
1535
|
+
"fetch_plugins_by_planner",
|
|
1536
|
+
"fetch_planner_bundle_functions",
|
|
1537
|
+
"fetch_functions_by_plugins",
|
|
1538
|
+
"fetch_plugin_instructions",
|
|
1539
|
+
"fetch_plugin_functions",
|
|
1540
|
+
"fetch_planner_attrs",
|
|
1541
|
+
"fetch_apex_bodies_by_names",
|
|
1542
|
+
"fetch_flow_definition_ids_by_names",
|
|
1543
|
+
"fetch_flow_metadata",
|
|
1544
|
+
"fetch_bot_versions",
|
|
1545
|
+
"fetch_bot_definition_details",
|
|
1546
|
+
)
|
|
1547
|
+
}
|
|
1548
|
+
finally:
|
|
1549
|
+
for p in patches:
|
|
1550
|
+
p.stop()
|
|
1551
|
+
|
|
1552
|
+
self.assertEqual(rc, 0)
|
|
1553
|
+
|
|
1554
|
+
# Every Wave-A + Wave-B fetcher received `api_version="v66.0"`.
|
|
1555
|
+
# We inspect call_args.kwargs rather than positional args — the
|
|
1556
|
+
# kwarg is keyword-only by design.
|
|
1557
|
+
expected = "v66.0"
|
|
1558
|
+
for name, calls in fetcher_call_lists.items():
|
|
1559
|
+
calls_with_version = [
|
|
1560
|
+
c for c in calls
|
|
1561
|
+
if c.kwargs.get("api_version") == expected
|
|
1562
|
+
]
|
|
1563
|
+
self.assertTrue(
|
|
1564
|
+
calls_with_version,
|
|
1565
|
+
f"{name}: no call observed with api_version={expected!r}. "
|
|
1566
|
+
f"All calls: {calls}",
|
|
1567
|
+
)
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
class UncaughtExceptionToResultBlockTests(unittest.TestCase):
|
|
1571
|
+
"""the skill contract says every exit path emits a RESULT
|
|
1572
|
+
block. Before the fix, an uncaught exception in the pipeline (e.g.
|
|
1573
|
+
the HTTP 405 from , or any future bug) propagated to the
|
|
1574
|
+
process boundary — users saw a Python traceback on stderr and the
|
|
1575
|
+
wrapper skill never got `.emit_ctx.json`. `main()` now wraps
|
|
1576
|
+
`_run_pipeline` in `try/except Exception` and funnels failures
|
|
1577
|
+
through `_emit_fail(..., "RETRIEVE_FAILED", "uncaught-exception: ...")`.
|
|
1578
|
+
"""
|
|
1579
|
+
|
|
1580
|
+
def test_uncaught_exception_surfaces_as_retrieve_failed(self):
|
|
1581
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1582
|
+
work_dir = Path(tmp) / "work"
|
|
1583
|
+
|
|
1584
|
+
# Patch `_run_pipeline` to raise an arbitrary non-HTTP bug
|
|
1585
|
+
# shape — proves the wrapper catches broad `Exception`, not
|
|
1586
|
+
# just the specific HTTPError from .
|
|
1587
|
+
with mock.patch.object(
|
|
1588
|
+
main, "_run_pipeline",
|
|
1589
|
+
side_effect=RuntimeError("unexpected defect in phase 6"),
|
|
1590
|
+
):
|
|
1591
|
+
rc = main.main(_args(work_dir))
|
|
1592
|
+
|
|
1593
|
+
# Exit code MUST be non-zero (failure signal) but controlled —
|
|
1594
|
+
# no Python traceback on stderr.
|
|
1595
|
+
self.assertEqual(rc, 1)
|
|
1596
|
+
|
|
1597
|
+
# `.emit_ctx.json` MUST exist — the skill contract.
|
|
1598
|
+
ctx_path = work_dir / ".emit_ctx.json"
|
|
1599
|
+
self.assertTrue(ctx_path.is_file(),
|
|
1600
|
+
"uncaught exception must still write .emit_ctx.json")
|
|
1601
|
+
ctx = _read_ctx(work_dir)
|
|
1602
|
+
self.assertEqual(ctx["status"], "RETRIEVE_FAILED")
|
|
1603
|
+
self.assertIn("uncaught-exception", ctx["error_detail"])
|
|
1604
|
+
self.assertIn("RuntimeError", ctx["error_detail"])
|
|
1605
|
+
self.assertIn("unexpected defect in phase 6", ctx["error_detail"])
|
|
1606
|
+
|
|
1607
|
+
def test_uncaught_exception_redacts_bearer_tokens(self):
|
|
1608
|
+
"""the redacted error_detail must not leak tokens even if
|
|
1609
|
+
the exception message happens to carry one."""
|
|
1610
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1611
|
+
work_dir = Path(tmp) / "work"
|
|
1612
|
+
|
|
1613
|
+
leaky = RuntimeError(
|
|
1614
|
+
"downstream failed: Authorization: Bearer TESTONLY_LEAKY_TOKEN"
|
|
1615
|
+
)
|
|
1616
|
+
with mock.patch.object(main, "_run_pipeline", side_effect=leaky):
|
|
1617
|
+
rc = main.main(_args(work_dir))
|
|
1618
|
+
|
|
1619
|
+
self.assertEqual(rc, 1)
|
|
1620
|
+
ctx = _read_ctx(work_dir)
|
|
1621
|
+
self.assertEqual(ctx["status"], "RETRIEVE_FAILED")
|
|
1622
|
+
# Token must NOT appear.
|
|
1623
|
+
self.assertNotIn("TESTONLY_LEAKY_TOKEN", ctx["error_detail"])
|
|
1624
|
+
# Redaction sentinel must appear — proof the scrub ran.
|
|
1625
|
+
self.assertIn("<redacted>", ctx["error_detail"])
|
|
1626
|
+
|
|
1627
|
+
def test_systemexit_still_propagates(self):
|
|
1628
|
+
"""argparse's --help path raises SystemExit. That MUST propagate
|
|
1629
|
+
unchanged — catching it would silently swallow `--help` + any
|
|
1630
|
+
other intentional early exit. The wrapper catches `Exception`,
|
|
1631
|
+
not `BaseException`, so SystemExit is unaffected."""
|
|
1632
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1633
|
+
work_dir = Path(tmp) / "work"
|
|
1634
|
+
|
|
1635
|
+
with mock.patch.object(main, "_run_pipeline",
|
|
1636
|
+
side_effect=SystemExit(2)):
|
|
1637
|
+
with self.assertRaises(SystemExit) as ctx:
|
|
1638
|
+
main.main(_args(work_dir))
|
|
1639
|
+
self.assertEqual(ctx.exception.code, 2)
|
|
1640
|
+
|
|
1641
|
+
|
|
1642
|
+
class NormalizeFlowIdTargetsTests(unittest.TestCase):
|
|
1643
|
+
"""classic bots occasionally store NGA-style
|
|
1644
|
+
300Uv-prefix FlowDefinition IDs or 301-prefix Flow version IDs as
|
|
1645
|
+
InvocationTarget. After Wave B resolves them we rewrite bundle_parsed
|
|
1646
|
+
in place so parse_wave sees DeveloperNames and the pending/visited
|
|
1647
|
+
diff collapses to zero for legitimate targets."""
|
|
1648
|
+
|
|
1649
|
+
def test_rewrites_flowdefinition_id_to_developer_name(self):
|
|
1650
|
+
bundle = {
|
|
1651
|
+
"topics": [{
|
|
1652
|
+
"name": "T",
|
|
1653
|
+
"actions": [{
|
|
1654
|
+
"name": "A",
|
|
1655
|
+
"invocationTarget": "300UvXXXXXXXXXXXX",
|
|
1656
|
+
"invocationTargetType": "flow",
|
|
1657
|
+
}],
|
|
1658
|
+
}],
|
|
1659
|
+
"plannerActions": [],
|
|
1660
|
+
}
|
|
1661
|
+
flow_def_rows = [{
|
|
1662
|
+
"Id": "300UvXXXXXXXXXXXX",
|
|
1663
|
+
"DeveloperName": "MyFlowName",
|
|
1664
|
+
"ActiveVersionId": "301VfYYYYYYYYYYYY",
|
|
1665
|
+
}]
|
|
1666
|
+
main._normalize_flow_id_targets(bundle, flow_def_rows)
|
|
1667
|
+
action = bundle["topics"][0]["actions"][0]
|
|
1668
|
+
self.assertEqual(action["invocationTarget"], "MyFlowName")
|
|
1669
|
+
self.assertEqual(action["_original_invocation_target_id"],
|
|
1670
|
+
"300UvXXXXXXXXXXXX")
|
|
1671
|
+
|
|
1672
|
+
def test_rewrites_flow_version_id_via_active_version_map(self):
|
|
1673
|
+
"""301-prefix IDs should also resolve — via the ActiveVersionId
|
|
1674
|
+
side of the bi-directional map."""
|
|
1675
|
+
bundle = {
|
|
1676
|
+
"topics": [{
|
|
1677
|
+
"actions": [{
|
|
1678
|
+
"invocationTarget": "301VfYYYYYYYYYYYY",
|
|
1679
|
+
"invocationTargetType": "flow",
|
|
1680
|
+
}],
|
|
1681
|
+
}],
|
|
1682
|
+
"plannerActions": [],
|
|
1683
|
+
}
|
|
1684
|
+
flow_def_rows = [{
|
|
1685
|
+
"Id": "300UvXXXXXXXXXXXX",
|
|
1686
|
+
"DeveloperName": "MyFlowName",
|
|
1687
|
+
"ActiveVersionId": "301VfYYYYYYYYYYYY",
|
|
1688
|
+
}]
|
|
1689
|
+
main._normalize_flow_id_targets(bundle, flow_def_rows)
|
|
1690
|
+
self.assertEqual(
|
|
1691
|
+
bundle["topics"][0]["actions"][0]["invocationTarget"],
|
|
1692
|
+
"MyFlowName",
|
|
1693
|
+
)
|
|
1694
|
+
|
|
1695
|
+
def test_preserves_classic_developer_name_targets(self):
|
|
1696
|
+
"""Classic DeveloperName targets must pass through untouched —
|
|
1697
|
+
they have nothing to resolve AND shouldn't pick up the sentinel
|
|
1698
|
+
_original_invocation_target_id field."""
|
|
1699
|
+
bundle = {
|
|
1700
|
+
"topics": [{
|
|
1701
|
+
"actions": [{
|
|
1702
|
+
"invocationTarget": "AGNT_Case_Create",
|
|
1703
|
+
"invocationTargetType": "flow",
|
|
1704
|
+
}],
|
|
1705
|
+
}],
|
|
1706
|
+
"plannerActions": [],
|
|
1707
|
+
}
|
|
1708
|
+
flow_def_rows = [{
|
|
1709
|
+
"Id": "300UvXXXXXXXXXXXX",
|
|
1710
|
+
"DeveloperName": "AGNT_Case_Create",
|
|
1711
|
+
"ActiveVersionId": "301VfYYYYYYYYYYYY",
|
|
1712
|
+
}]
|
|
1713
|
+
main._normalize_flow_id_targets(bundle, flow_def_rows)
|
|
1714
|
+
action = bundle["topics"][0]["actions"][0]
|
|
1715
|
+
self.assertEqual(action["invocationTarget"], "AGNT_Case_Create")
|
|
1716
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
1717
|
+
|
|
1718
|
+
def test_unmatched_id_stays_as_is(self):
|
|
1719
|
+
"""An ID that doesn't appear in flow_def_rows (Flow not queryable
|
|
1720
|
+
/ managed package invisible) stays unchanged — that's how it
|
|
1721
|
+
correctly surfaces in _pending_fetches instead of silently
|
|
1722
|
+
discarding."""
|
|
1723
|
+
bundle = {
|
|
1724
|
+
"topics": [{
|
|
1725
|
+
"actions": [{
|
|
1726
|
+
"invocationTarget": "300UvZZZZZZZZZZZZ",
|
|
1727
|
+
"invocationTargetType": "flow",
|
|
1728
|
+
}],
|
|
1729
|
+
}],
|
|
1730
|
+
"plannerActions": [],
|
|
1731
|
+
}
|
|
1732
|
+
main._normalize_flow_id_targets(bundle, [{
|
|
1733
|
+
"Id": "300UvXXXXXXXXXXXX",
|
|
1734
|
+
"DeveloperName": "DifferentFlow",
|
|
1735
|
+
"ActiveVersionId": "301VfYYYYYYYYYYYY",
|
|
1736
|
+
}])
|
|
1737
|
+
self.assertEqual(
|
|
1738
|
+
bundle["topics"][0]["actions"][0]["invocationTarget"],
|
|
1739
|
+
"300UvZZZZZZZZZZZZ",
|
|
1740
|
+
)
|
|
1741
|
+
|
|
1742
|
+
def test_apex_target_with_300_prefix_not_rewritten(self):
|
|
1743
|
+
"""Only invocationTargetType=='flow' is rewritten. A target that
|
|
1744
|
+
happens to match a flow id but is declared as apex stays put —
|
|
1745
|
+
it's a caller-error we surface, not one we silently rewrite."""
|
|
1746
|
+
bundle = {
|
|
1747
|
+
"topics": [{
|
|
1748
|
+
"actions": [{
|
|
1749
|
+
"invocationTarget": "300UvXXXXXXXXXXXX",
|
|
1750
|
+
"invocationTargetType": "apex", # wrong type
|
|
1751
|
+
}],
|
|
1752
|
+
}],
|
|
1753
|
+
"plannerActions": [],
|
|
1754
|
+
}
|
|
1755
|
+
flow_def_rows = [{
|
|
1756
|
+
"Id": "300UvXXXXXXXXXXXX",
|
|
1757
|
+
"DeveloperName": "MyFlow",
|
|
1758
|
+
"ActiveVersionId": "301VfYYYYYYYYYYYY",
|
|
1759
|
+
}]
|
|
1760
|
+
main._normalize_flow_id_targets(bundle, flow_def_rows)
|
|
1761
|
+
self.assertEqual(
|
|
1762
|
+
bundle["topics"][0]["actions"][0]["invocationTarget"],
|
|
1763
|
+
"300UvXXXXXXXXXXXX",
|
|
1764
|
+
)
|
|
1765
|
+
|
|
1766
|
+
def test_empty_inputs_noop(self):
|
|
1767
|
+
"""Empty flow_def_rows → immediate return, no mutation, no crash
|
|
1768
|
+
on missing 'topics' / 'plannerActions' keys."""
|
|
1769
|
+
bundle = {}
|
|
1770
|
+
main._normalize_flow_id_targets(bundle, [])
|
|
1771
|
+
self.assertEqual(bundle, {})
|
|
1772
|
+
|
|
1773
|
+
bundle2 = {
|
|
1774
|
+
"topics": [{"actions": [{
|
|
1775
|
+
"invocationTarget": "300Uv", "invocationTargetType": "flow",
|
|
1776
|
+
}]}],
|
|
1777
|
+
"plannerActions": [],
|
|
1778
|
+
}
|
|
1779
|
+
main._normalize_flow_id_targets(bundle2, [])
|
|
1780
|
+
# Untouched — no lookup map to rewrite against.
|
|
1781
|
+
self.assertEqual(
|
|
1782
|
+
bundle2["topics"][0]["actions"][0]["invocationTarget"], "300Uv",
|
|
1783
|
+
)
|
|
1784
|
+
|
|
1785
|
+
def test_rewrites_both_topics_and_planner_actions(self):
|
|
1786
|
+
"""Fix must cover both the per-topic actions path AND the
|
|
1787
|
+
bundle-scope plannerActions path."""
|
|
1788
|
+
bundle = {
|
|
1789
|
+
"topics": [{
|
|
1790
|
+
"actions": [{
|
|
1791
|
+
"invocationTarget": "300UvAAAA",
|
|
1792
|
+
"invocationTargetType": "flow",
|
|
1793
|
+
}],
|
|
1794
|
+
}],
|
|
1795
|
+
"plannerActions": [{
|
|
1796
|
+
"invocationTarget": "300UvBBBB",
|
|
1797
|
+
"invocationTargetType": "flow",
|
|
1798
|
+
}],
|
|
1799
|
+
}
|
|
1800
|
+
flow_def_rows = [
|
|
1801
|
+
{"Id": "300UvAAAA", "DeveloperName": "TopicFlow",
|
|
1802
|
+
"ActiveVersionId": "301AAAA"},
|
|
1803
|
+
{"Id": "300UvBBBB", "DeveloperName": "BundleFlow",
|
|
1804
|
+
"ActiveVersionId": "301BBBB"},
|
|
1805
|
+
]
|
|
1806
|
+
main._normalize_flow_id_targets(bundle, flow_def_rows)
|
|
1807
|
+
self.assertEqual(
|
|
1808
|
+
bundle["topics"][0]["actions"][0]["invocationTarget"], "TopicFlow",
|
|
1809
|
+
)
|
|
1810
|
+
self.assertEqual(
|
|
1811
|
+
bundle["plannerActions"][0]["invocationTarget"], "BundleFlow",
|
|
1812
|
+
)
|
|
1813
|
+
|
|
1814
|
+
def test_none_invocation_target_type_ignored_safely(self):
|
|
1815
|
+
"""Defensive: invocationTargetType missing → treat as 'not a
|
|
1816
|
+
flow', skip. No crash."""
|
|
1817
|
+
bundle = {
|
|
1818
|
+
"topics": [{"actions": [{
|
|
1819
|
+
"invocationTarget": "300UvAAAA",
|
|
1820
|
+
"invocationTargetType": None,
|
|
1821
|
+
}]}],
|
|
1822
|
+
"plannerActions": [],
|
|
1823
|
+
}
|
|
1824
|
+
main._normalize_flow_id_targets(bundle, [
|
|
1825
|
+
{"Id": "300UvAAAA", "DeveloperName": "X", "ActiveVersionId": "301"}
|
|
1826
|
+
])
|
|
1827
|
+
self.assertEqual(
|
|
1828
|
+
bundle["topics"][0]["actions"][0]["invocationTarget"], "300UvAAAA",
|
|
1829
|
+
)
|
|
1830
|
+
|
|
1831
|
+
|
|
1832
|
+
class CollectWaveBTargetsStandardActionTests(unittest.TestCase):
|
|
1833
|
+
"""`_route` in `_collect_wave_b_targets` must
|
|
1834
|
+
short-circuit on declared-only target types (standardInvocableAction,
|
|
1835
|
+
generatePromptResponse, genai*, prompt*) BEFORE calling
|
|
1836
|
+
resolve_or_unresolved — otherwise it pollutes `_unresolved` with
|
|
1837
|
+
spurious "invalid-id-format" entries for perfectly valid identifiers
|
|
1838
|
+
that simply aren't Salesforce Ids."""
|
|
1839
|
+
|
|
1840
|
+
def test_standard_action_not_routed_through_id_resolver(self):
|
|
1841
|
+
"""`streamKnowledgeSearch` is a built-in standard action — not
|
|
1842
|
+
an Id. It should not end up in apex_ids, flow_ids, apex_names,
|
|
1843
|
+
or flow_names AND it should NOT appear in the `_unresolved`
|
|
1844
|
+
list that resolve_or_unresolved populates on non-Id inputs.
|
|
1845
|
+
"""
|
|
1846
|
+
bundle = {
|
|
1847
|
+
"topics": [{
|
|
1848
|
+
"name": "T",
|
|
1849
|
+
"actions": [{
|
|
1850
|
+
"name": "A",
|
|
1851
|
+
"invocationTarget": "streamKnowledgeSearch",
|
|
1852
|
+
"invocationTargetType": "standardInvocableAction",
|
|
1853
|
+
}],
|
|
1854
|
+
}],
|
|
1855
|
+
"plannerActions": [],
|
|
1856
|
+
}
|
|
1857
|
+
result = main._collect_wave_b_targets(bundle)
|
|
1858
|
+
self.assertEqual(result["apex_names"], [])
|
|
1859
|
+
self.assertEqual(result["apex_ids"], [])
|
|
1860
|
+
self.assertEqual(result["flow_names"], [])
|
|
1861
|
+
self.assertEqual(result["flow_ids"], [])
|
|
1862
|
+
self.assertEqual(
|
|
1863
|
+
result["_unresolved"], [],
|
|
1864
|
+
"standardInvocableAction must not pollute _unresolved with "
|
|
1865
|
+
"invalid-id-format entries",
|
|
1866
|
+
)
|
|
1867
|
+
|
|
1868
|
+
def test_generate_prompt_response_short_circuits(self):
|
|
1869
|
+
"""`generatePromptResponse` targets are prompt-template names;
|
|
1870
|
+
not routed to Apex/Flow fetchers (Batch 1 is body-only for
|
|
1871
|
+
Apex+Flow; prompts flow through the retrieve path)."""
|
|
1872
|
+
bundle = {
|
|
1873
|
+
"topics": [{
|
|
1874
|
+
"name": "T",
|
|
1875
|
+
"actions": [{
|
|
1876
|
+
"invocationTarget": "MyPromptTemplate",
|
|
1877
|
+
"invocationTargetType": "generatePromptResponse",
|
|
1878
|
+
}],
|
|
1879
|
+
}],
|
|
1880
|
+
"plannerActions": [],
|
|
1881
|
+
}
|
|
1882
|
+
result = main._collect_wave_b_targets(bundle)
|
|
1883
|
+
self.assertEqual(result["apex_names"], [])
|
|
1884
|
+
self.assertEqual(result["flow_names"], [])
|
|
1885
|
+
self.assertEqual(result["_unresolved"], [])
|
|
1886
|
+
|
|
1887
|
+
def test_flow_and_apex_still_route_correctly(self):
|
|
1888
|
+
"""Positive control — the short-circuit must not break flow/apex
|
|
1889
|
+
routing. A mix of classic DeveloperNames + NGA IDs should land in
|
|
1890
|
+
the right buckets, and standard actions should pass through
|
|
1891
|
+
without polluting anything."""
|
|
1892
|
+
bundle = {
|
|
1893
|
+
"topics": [{
|
|
1894
|
+
"name": "T",
|
|
1895
|
+
"actions": [
|
|
1896
|
+
# Classic flow by DeveloperName
|
|
1897
|
+
{"invocationTarget": "MyFlow",
|
|
1898
|
+
"invocationTargetType": "flow"},
|
|
1899
|
+
# Classic apex by name
|
|
1900
|
+
{"invocationTarget": "MyApex",
|
|
1901
|
+
"invocationTargetType": "apex"},
|
|
1902
|
+
# Standard action (new short-circuit path)
|
|
1903
|
+
{"invocationTarget": "streamKnowledgeSearch",
|
|
1904
|
+
"invocationTargetType": "standardInvocableAction"},
|
|
1905
|
+
# NGA apex by Id
|
|
1906
|
+
{"invocationTarget": "01p1N000005SsDNQA0",
|
|
1907
|
+
"invocationTargetType": "apex"},
|
|
1908
|
+
],
|
|
1909
|
+
}],
|
|
1910
|
+
"plannerActions": [],
|
|
1911
|
+
}
|
|
1912
|
+
result = main._collect_wave_b_targets(bundle)
|
|
1913
|
+
self.assertIn("MyFlow", result["flow_names"])
|
|
1914
|
+
self.assertIn("MyApex", result["apex_names"])
|
|
1915
|
+
self.assertIn("01p1N000005SsDNQA0", result["apex_ids"])
|
|
1916
|
+
self.assertEqual(result["_unresolved"], [])
|
|
1917
|
+
|
|
1918
|
+
def test_unknown_type_silently_skipped(self):
|
|
1919
|
+
"""An unrecognized invocationTargetType falls through all the
|
|
1920
|
+
known-type branches and is silently skipped. parse_wave tags the
|
|
1921
|
+
node as UNKNOWN in the tree (via `_kind_counts`), so the signal
|
|
1922
|
+
is visible without polluting _unresolved."""
|
|
1923
|
+
bundle = {
|
|
1924
|
+
"topics": [{
|
|
1925
|
+
"name": "T",
|
|
1926
|
+
"actions": [{
|
|
1927
|
+
"invocationTarget": "SomeThing",
|
|
1928
|
+
"invocationTargetType": "unheardOfType",
|
|
1929
|
+
}],
|
|
1930
|
+
}],
|
|
1931
|
+
"plannerActions": [],
|
|
1932
|
+
}
|
|
1933
|
+
result = main._collect_wave_b_targets(bundle)
|
|
1934
|
+
self.assertEqual(result["apex_names"], [])
|
|
1935
|
+
self.assertEqual(result["flow_names"], [])
|
|
1936
|
+
self.assertEqual(
|
|
1937
|
+
result["_unresolved"], [],
|
|
1938
|
+
"Unknown invocationTargetType shouldn't reach the ID router, "
|
|
1939
|
+
"so _unresolved stays clean.",
|
|
1940
|
+
)
|
|
1941
|
+
|
|
1942
|
+
def test_classic_flow_name_not_routed_through_id_resolver(self):
|
|
1943
|
+
"""classic bots store plain DeveloperNames
|
|
1944
|
+
like `MyFlow` — not Salesforce Ids. The router must route these
|
|
1945
|
+
directly to flow_names via invocationTargetType, NOT through
|
|
1946
|
+
resolve_or_unresolved (which would reject them as invalid-id-
|
|
1947
|
+
format and pollute _unresolved)."""
|
|
1948
|
+
bundle = {
|
|
1949
|
+
"topics": [{
|
|
1950
|
+
"actions": [
|
|
1951
|
+
{"invocationTarget": "MyFlow",
|
|
1952
|
+
"invocationTargetType": "flow"},
|
|
1953
|
+
{"invocationTarget": "AGNT_Foo",
|
|
1954
|
+
"invocationTargetType": "apex"},
|
|
1955
|
+
],
|
|
1956
|
+
}],
|
|
1957
|
+
"plannerActions": [],
|
|
1958
|
+
}
|
|
1959
|
+
result = main._collect_wave_b_targets(bundle)
|
|
1960
|
+
self.assertIn("MyFlow", result["flow_names"])
|
|
1961
|
+
self.assertIn("AGNT_Foo", result["apex_names"])
|
|
1962
|
+
self.assertEqual(
|
|
1963
|
+
result["_unresolved"], [],
|
|
1964
|
+
"Classic DeveloperNames shouldn't be sent through the ID "
|
|
1965
|
+
"resolver at all — they're not Ids.",
|
|
1966
|
+
)
|
|
1967
|
+
|
|
1968
|
+
|
|
1969
|
+
class NormalizePromptTemplateIdTargetsTests(unittest.TestCase):
|
|
1970
|
+
"""Bug 1 fix (2026-05-05): classic bots occasionally store 0hf-prefix
|
|
1971
|
+
GenAiPromptTemplate IDs as `GenAiFunctionDefinition.InvocationTarget`.
|
|
1972
|
+
After Wave B resolves them via `list_prompt_template_metadata`
|
|
1973
|
+
(GenAiPromptTemplate is NOT SOQL-queryable — Metadata API only) we
|
|
1974
|
+
rewrite bundle_parsed in place so Wave B's retrieve uses the
|
|
1975
|
+
DeveloperName Metadata API expects."""
|
|
1976
|
+
|
|
1977
|
+
def test_rewrites_prompt_template_id_to_developer_name(self):
|
|
1978
|
+
bundle = {
|
|
1979
|
+
"topics": [{
|
|
1980
|
+
"actions": [{
|
|
1981
|
+
"invocationTarget": "0hfUv0000021mCjIAI",
|
|
1982
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
1983
|
+
}],
|
|
1984
|
+
}],
|
|
1985
|
+
"plannerActions": [],
|
|
1986
|
+
}
|
|
1987
|
+
rows = [{"Id": "0hfUv0000021mCjIAI", "DeveloperName": "My_Prompt"}]
|
|
1988
|
+
main._normalize_prompt_template_id_targets(bundle, rows)
|
|
1989
|
+
action = bundle["topics"][0]["actions"][0]
|
|
1990
|
+
self.assertEqual(action["invocationTarget"], "My_Prompt")
|
|
1991
|
+
self.assertEqual(
|
|
1992
|
+
action["_original_invocation_target_id"], "0hfUv0000021mCjIAI"
|
|
1993
|
+
)
|
|
1994
|
+
|
|
1995
|
+
def test_preserves_classic_developer_name_targets(self):
|
|
1996
|
+
"""Classic DeveloperName targets pass through untouched — the
|
|
1997
|
+
rewrite is only for Id-shaped targets that appeared in the lookup."""
|
|
1998
|
+
bundle = {
|
|
1999
|
+
"topics": [{
|
|
2000
|
+
"actions": [{
|
|
2001
|
+
"invocationTarget": "Existing_Prompt_Name",
|
|
2002
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
2003
|
+
}],
|
|
2004
|
+
}],
|
|
2005
|
+
"plannerActions": [],
|
|
2006
|
+
}
|
|
2007
|
+
# Lookup covers a different Id entirely — the DeveloperName target
|
|
2008
|
+
# isn't a key in the map so it's not rewritten.
|
|
2009
|
+
rows = [{"Id": "0hfUv0000021Other", "DeveloperName": "Other_Prompt"}]
|
|
2010
|
+
main._normalize_prompt_template_id_targets(bundle, rows)
|
|
2011
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2012
|
+
self.assertEqual(action["invocationTarget"], "Existing_Prompt_Name")
|
|
2013
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
2014
|
+
|
|
2015
|
+
def test_unmatched_id_stays_as_is(self):
|
|
2016
|
+
"""Id not present in the lookup (e.g. Tooling returned empty
|
|
2017
|
+
because GenAiPromptTemplate isn't exposed on this org) stays
|
|
2018
|
+
as-is so it correctly surfaces in _pending_fetches."""
|
|
2019
|
+
bundle = {
|
|
2020
|
+
"topics": [{
|
|
2021
|
+
"actions": [{
|
|
2022
|
+
"invocationTarget": "0hfUv00000xxxxxYYY",
|
|
2023
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
2024
|
+
}],
|
|
2025
|
+
}],
|
|
2026
|
+
"plannerActions": [],
|
|
2027
|
+
}
|
|
2028
|
+
main._normalize_prompt_template_id_targets(bundle, [])
|
|
2029
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2030
|
+
self.assertEqual(action["invocationTarget"], "0hfUv00000xxxxxYYY")
|
|
2031
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
2032
|
+
|
|
2033
|
+
|
|
2034
|
+
class NormalizeApexIdTargetsTests(unittest.TestCase):
|
|
2035
|
+
"""Gap B fix (2026-05-05): classic bots occasionally store 01p-prefix
|
|
2036
|
+
ApexClass Ids as `GenAiFunctionDefinition.InvocationTarget` (live-verified
|
|
2037
|
+
on my-org-alias: 01p000000000000AAA -> MyController).
|
|
2038
|
+
After Wave B resolves them via `fetch_apex_bodies_by_ids` we rewrite
|
|
2039
|
+
bundle_parsed in place so the tree renders the ApexClass Name instead
|
|
2040
|
+
of the raw Id."""
|
|
2041
|
+
|
|
2042
|
+
def test_rewrites_apex_id_to_class_name(self):
|
|
2043
|
+
bundle = {
|
|
2044
|
+
"topics": [{
|
|
2045
|
+
"actions": [{
|
|
2046
|
+
"invocationTarget": "01p000000000000AAA",
|
|
2047
|
+
"invocationTargetType": "apex",
|
|
2048
|
+
}],
|
|
2049
|
+
}],
|
|
2050
|
+
"plannerActions": [],
|
|
2051
|
+
}
|
|
2052
|
+
rows = [{"Id": "01p000000000000AAA", "Name": "MyController"}]
|
|
2053
|
+
main._normalize_apex_id_targets(bundle, rows)
|
|
2054
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2055
|
+
self.assertEqual(action["invocationTarget"], "MyController")
|
|
2056
|
+
self.assertEqual(
|
|
2057
|
+
action["_original_invocation_target_id"], "01p000000000000AAA"
|
|
2058
|
+
)
|
|
2059
|
+
|
|
2060
|
+
def test_non_apex_ttype_left_unchanged(self):
|
|
2061
|
+
"""Same Id but a non-apex ttype — the ttype gate must block the
|
|
2062
|
+
rewrite so a Flow action whose target happens to collide with an
|
|
2063
|
+
ApexClass Id isn't miscaught."""
|
|
2064
|
+
bundle = {
|
|
2065
|
+
"topics": [{
|
|
2066
|
+
"actions": [{
|
|
2067
|
+
"invocationTarget": "01p000000000000AAA",
|
|
2068
|
+
"invocationTargetType": "flow",
|
|
2069
|
+
}],
|
|
2070
|
+
}],
|
|
2071
|
+
"plannerActions": [],
|
|
2072
|
+
}
|
|
2073
|
+
rows = [{"Id": "01p000000000000AAA", "Name": "MyController"}]
|
|
2074
|
+
main._normalize_apex_id_targets(bundle, rows)
|
|
2075
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2076
|
+
self.assertEqual(action["invocationTarget"], "01p000000000000AAA")
|
|
2077
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
2078
|
+
|
|
2079
|
+
def test_unmatched_id_stays_as_is(self):
|
|
2080
|
+
"""Id not present in the lookup (e.g. by-Id fetch failed or the
|
|
2081
|
+
class was deleted) stays as-is so it correctly surfaces in
|
|
2082
|
+
_pending_fetches."""
|
|
2083
|
+
bundle = {
|
|
2084
|
+
"topics": [{
|
|
2085
|
+
"actions": [{
|
|
2086
|
+
"invocationTarget": "01pFAKEIDFAKEIDAAA",
|
|
2087
|
+
"invocationTargetType": "apex",
|
|
2088
|
+
}],
|
|
2089
|
+
}],
|
|
2090
|
+
"plannerActions": [],
|
|
2091
|
+
}
|
|
2092
|
+
main._normalize_apex_id_targets(bundle, [])
|
|
2093
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2094
|
+
self.assertEqual(action["invocationTarget"], "01pFAKEIDFAKEIDAAA")
|
|
2095
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
2096
|
+
|
|
2097
|
+
def test_preserves_classic_developer_name_targets(self):
|
|
2098
|
+
"""Classic Name targets pass through untouched — the rewrite is
|
|
2099
|
+
only for Id-shaped targets (01p-prefix) that appeared in the lookup."""
|
|
2100
|
+
bundle = {
|
|
2101
|
+
"topics": [{
|
|
2102
|
+
"actions": [{
|
|
2103
|
+
"invocationTarget": "MyApexClass",
|
|
2104
|
+
"invocationTargetType": "apex",
|
|
2105
|
+
}],
|
|
2106
|
+
}],
|
|
2107
|
+
"plannerActions": [],
|
|
2108
|
+
}
|
|
2109
|
+
# Lookup covers a different Id entirely — the Name target isn't
|
|
2110
|
+
# Id-shaped and doesn't hit the prefix gate.
|
|
2111
|
+
rows = [{"Id": "01p000000000000AAA", "Name": "MyController"}]
|
|
2112
|
+
main._normalize_apex_id_targets(bundle, rows)
|
|
2113
|
+
action = bundle["topics"][0]["actions"][0]
|
|
2114
|
+
self.assertEqual(action["invocationTarget"], "MyApexClass")
|
|
2115
|
+
self.assertNotIn("_original_invocation_target_id", action)
|
|
2116
|
+
|
|
2117
|
+
|
|
2118
|
+
class CollectWaveBTargetsPromptTemplateIdTests(unittest.TestCase):
|
|
2119
|
+
"""Bug 1 fix (2026-05-05): 0hf-prefix prompt template Ids are routed
|
|
2120
|
+
to a dedicated `prompt_template_ids` bucket so post-Wave-B resolution
|
|
2121
|
+
can rewrite them; DeveloperName targets still short-circuit as before."""
|
|
2122
|
+
|
|
2123
|
+
def test_prompt_template_id_routes_to_id_bucket(self):
|
|
2124
|
+
bundle = {
|
|
2125
|
+
"topics": [],
|
|
2126
|
+
"plannerActions": [{
|
|
2127
|
+
"invocationTarget": "0hfUv0000021mCjIAI",
|
|
2128
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
2129
|
+
}],
|
|
2130
|
+
}
|
|
2131
|
+
result = main._collect_wave_b_targets(bundle)
|
|
2132
|
+
self.assertEqual(
|
|
2133
|
+
result.get("prompt_template_ids"), ["0hfUv0000021mCjIAI"]
|
|
2134
|
+
)
|
|
2135
|
+
# DeveloperName bucket stays empty — the Id is routed to the Id
|
|
2136
|
+
# bucket and the short-circuit returns BEFORE the DeveloperName
|
|
2137
|
+
# branch would have run.
|
|
2138
|
+
self.assertEqual(result.get("_unresolved"), [])
|
|
2139
|
+
|
|
2140
|
+
def test_prompt_template_developer_name_does_not_pollute_id_bucket(self):
|
|
2141
|
+
bundle = {
|
|
2142
|
+
"topics": [],
|
|
2143
|
+
"plannerActions": [{
|
|
2144
|
+
"invocationTarget": "My_Prompt_Template_Name",
|
|
2145
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
2146
|
+
}],
|
|
2147
|
+
}
|
|
2148
|
+
result = main._collect_wave_b_targets(bundle)
|
|
2149
|
+
self.assertEqual(result.get("prompt_template_ids"), [])
|
|
2150
|
+
# DeveloperName-shaped prompt-template targets still short-circuit
|
|
2151
|
+
# (parse_wave enqueues them into PROMPT_TEMPLATE pending) — no
|
|
2152
|
+
# change from prior behavior, verified via absence from all
|
|
2153
|
+
# name/id buckets we'd route through.
|
|
2154
|
+
self.assertEqual(result.get("apex_names"), [])
|
|
2155
|
+
self.assertEqual(result.get("flow_names"), [])
|
|
2156
|
+
|
|
2157
|
+
def test_non_0hf_prefix_ignored(self):
|
|
2158
|
+
"""Id-shaped target for a prompt-template ttype but WRONG prefix
|
|
2159
|
+
(e.g. a Flow Id accidentally typed with prompt ttype) doesn't
|
|
2160
|
+
pollute prompt_template_ids — the prefix gate catches it."""
|
|
2161
|
+
bundle = {
|
|
2162
|
+
"topics": [],
|
|
2163
|
+
"plannerActions": [{
|
|
2164
|
+
"invocationTarget": "300Uv00000abcdeFGH", # Flow-shaped Id
|
|
2165
|
+
"invocationTargetType": "GenAiPromptTemplate",
|
|
2166
|
+
}],
|
|
2167
|
+
}
|
|
2168
|
+
result = main._collect_wave_b_targets(bundle)
|
|
2169
|
+
# Not routed anywhere — neither prompt-template Id bucket nor
|
|
2170
|
+
# flow buckets (ttype gated). Surfaces nowhere, which is
|
|
2171
|
+
# acceptable: classify_action_call downstream will still enqueue
|
|
2172
|
+
# the string as-is as a PROMPT_TEMPLATE pending fetch.
|
|
2173
|
+
self.assertEqual(result.get("prompt_template_ids"), [])
|
|
2174
|
+
|
|
2175
|
+
|
|
2176
|
+
class FetchFlowDefinitionViewByDurableIdsTests(unittest.TestCase):
|
|
2177
|
+
"""Option B (2026-05-05): `fetch_flow_definition_view_by_durable_ids`
|
|
2178
|
+
is the Data-API fallback fetcher for managed-installed flows that
|
|
2179
|
+
Tooling's `FlowDefinition` doesn't index.
|
|
2180
|
+
|
|
2181
|
+
Contract:
|
|
2182
|
+
* Empty input short-circuits to `[]` without firing a SOQL call
|
|
2183
|
+
(matches every other list-shaped fetcher in this module).
|
|
2184
|
+
* Rows are returned from `data_query` verbatim — projection to
|
|
2185
|
+
the `flow_def_rows` shape happens in the caller
|
|
2186
|
+
(`fetch_flow_definition_ids_by_names`).
|
|
2187
|
+
"""
|
|
2188
|
+
|
|
2189
|
+
def test_happy_path_returns_rows(self):
|
|
2190
|
+
import fetch_soql # type: ignore
|
|
2191
|
+
view_row = {
|
|
2192
|
+
"DurableId": "SvcCopilotTmpl__VerifyCode",
|
|
2193
|
+
"ApiName": "VerifyCode",
|
|
2194
|
+
"Label": "Verify Code",
|
|
2195
|
+
"NamespacePrefix": "SvcCopilotTmpl",
|
|
2196
|
+
"ActiveVersionId": "SvcCopilotTmpl__VerifyCode-1",
|
|
2197
|
+
"IsActive": True,
|
|
2198
|
+
"ManageableState": "installed",
|
|
2199
|
+
"ProcessType": "AutoLaunchedFlow",
|
|
2200
|
+
}
|
|
2201
|
+
with mock.patch.object(
|
|
2202
|
+
fetch_soql, "data_query",
|
|
2203
|
+
return_value={"records": [view_row]},
|
|
2204
|
+
) as mock_dq:
|
|
2205
|
+
rows = fetch_soql.fetch_flow_definition_view_by_durable_ids(
|
|
2206
|
+
["SvcCopilotTmpl__VerifyCode"],
|
|
2207
|
+
lambda: ("url", "tok"),
|
|
2208
|
+
api_version="v60.0",
|
|
2209
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2210
|
+
)
|
|
2211
|
+
self.assertEqual(rows, [view_row])
|
|
2212
|
+
# Exactly one data_query call — the fetcher doesn't accidentally
|
|
2213
|
+
# re-fire on the Tooling surface.
|
|
2214
|
+
self.assertEqual(mock_dq.call_count, 1)
|
|
2215
|
+
|
|
2216
|
+
def test_empty_input_short_circuits(self):
|
|
2217
|
+
"""Empty durable_ids list returns [] WITHOUT firing a SOQL call
|
|
2218
|
+
(matches the module-wide empty-input-short-circuit invariant)."""
|
|
2219
|
+
import fetch_soql # type: ignore
|
|
2220
|
+
with mock.patch.object(fetch_soql, "data_query") as mock_dq:
|
|
2221
|
+
rows = fetch_soql.fetch_flow_definition_view_by_durable_ids(
|
|
2222
|
+
[],
|
|
2223
|
+
lambda: ("url", "tok"),
|
|
2224
|
+
api_version="v60.0",
|
|
2225
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2226
|
+
)
|
|
2227
|
+
self.assertEqual(rows, [])
|
|
2228
|
+
self.assertEqual(mock_dq.call_count, 0)
|
|
2229
|
+
|
|
2230
|
+
def test_multi_row_returns_all(self):
|
|
2231
|
+
import fetch_soql # type: ignore
|
|
2232
|
+
view_rows = [
|
|
2233
|
+
{
|
|
2234
|
+
"DurableId": "SvcCopilotTmpl__VerifyCode",
|
|
2235
|
+
"ApiName": "VerifyCode",
|
|
2236
|
+
"NamespacePrefix": "SvcCopilotTmpl",
|
|
2237
|
+
"ActiveVersionId": "SvcCopilotTmpl__VerifyCode-1",
|
|
2238
|
+
"ManageableState": "installed",
|
|
2239
|
+
},
|
|
2240
|
+
{
|
|
2241
|
+
"DurableId": "sales_inbound_flows__SendVerifyCode",
|
|
2242
|
+
"ApiName": "SendVerifyCode",
|
|
2243
|
+
"NamespacePrefix": "sales_inbound_flows",
|
|
2244
|
+
"ActiveVersionId": "sales_inbound_flows__SendVerifyCode-2",
|
|
2245
|
+
"ManageableState": "installed",
|
|
2246
|
+
},
|
|
2247
|
+
]
|
|
2248
|
+
with mock.patch.object(
|
|
2249
|
+
fetch_soql, "data_query",
|
|
2250
|
+
return_value={"records": view_rows},
|
|
2251
|
+
):
|
|
2252
|
+
rows = fetch_soql.fetch_flow_definition_view_by_durable_ids(
|
|
2253
|
+
[
|
|
2254
|
+
"SvcCopilotTmpl__VerifyCode",
|
|
2255
|
+
"sales_inbound_flows__SendVerifyCode",
|
|
2256
|
+
],
|
|
2257
|
+
lambda: ("url", "tok"),
|
|
2258
|
+
api_version="v60.0",
|
|
2259
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2260
|
+
)
|
|
2261
|
+
self.assertEqual(len(rows), 2)
|
|
2262
|
+
# Membership assertion rather than sort-order — codepoint sort of
|
|
2263
|
+
# mixed-case prefixes is fragile; the fetcher returns rows in the
|
|
2264
|
+
# order `data_query` supplies them.
|
|
2265
|
+
self.assertEqual(
|
|
2266
|
+
{r["DurableId"] for r in rows},
|
|
2267
|
+
{
|
|
2268
|
+
"SvcCopilotTmpl__VerifyCode",
|
|
2269
|
+
"sales_inbound_flows__SendVerifyCode",
|
|
2270
|
+
},
|
|
2271
|
+
)
|
|
2272
|
+
|
|
2273
|
+
|
|
2274
|
+
class FlowDefinitionViewFallbackTests(unittest.TestCase):
|
|
2275
|
+
"""Option B (2026-05-05, updated after managed-bucket retirement):
|
|
2276
|
+
`fetch_flow_definition_ids_by_names` fires a SINGLE Tooling
|
|
2277
|
+
`FlowDefinition` query (unmanaged-only — the template filters
|
|
2278
|
+
`NamespacePrefix IS NULL`). Any input name that query doesn't resolve
|
|
2279
|
+
triggers a single follow-up `FlowDefinitionView` (Data API) query.
|
|
2280
|
+
Projected view-only rows carry `Id=None`, `ActiveVersionId=None`,
|
|
2281
|
+
`_body_available=False`, and `_source="FlowDefinitionView"`.
|
|
2282
|
+
"""
|
|
2283
|
+
|
|
2284
|
+
def test_fallback_fires_on_managed_miss(self):
|
|
2285
|
+
"""Tooling FlowDefinition returns empty for a `ns__Name` input
|
|
2286
|
+
(managed flows aren't indexed on subscriber orgs + the unmanaged
|
|
2287
|
+
query filters `NamespacePrefix IS NULL` anyway); FlowDefinitionView
|
|
2288
|
+
returns a matching row. Output row carries the view-shaped markers
|
|
2289
|
+
and `DeveloperName` = qualified ns__bare."""
|
|
2290
|
+
import fetch_soql # type: ignore
|
|
2291
|
+
view_row = {
|
|
2292
|
+
"DurableId": "SvcCopilotTmpl__VerifyCode",
|
|
2293
|
+
"ApiName": "VerifyCode",
|
|
2294
|
+
"Label": "Verify Code",
|
|
2295
|
+
"NamespacePrefix": "SvcCopilotTmpl",
|
|
2296
|
+
"ActiveVersionId": "SvcCopilotTmpl__VerifyCode-1",
|
|
2297
|
+
"ManageableState": "installed",
|
|
2298
|
+
}
|
|
2299
|
+
with mock.patch.object(
|
|
2300
|
+
fetch_soql, "tooling_query",
|
|
2301
|
+
return_value={"records": []},
|
|
2302
|
+
), mock.patch.object(
|
|
2303
|
+
fetch_soql, "data_query",
|
|
2304
|
+
return_value={"records": [view_row]},
|
|
2305
|
+
) as mock_dq:
|
|
2306
|
+
rows = fetch_soql.fetch_flow_definition_ids_by_names(
|
|
2307
|
+
["SvcCopilotTmpl__VerifyCode"],
|
|
2308
|
+
lambda: ("url", "tok"),
|
|
2309
|
+
api_version="v60.0",
|
|
2310
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2311
|
+
)
|
|
2312
|
+
self.assertEqual(len(rows), 1)
|
|
2313
|
+
row = rows[0]
|
|
2314
|
+
self.assertIsNone(row["Id"])
|
|
2315
|
+
self.assertIsNone(row["ActiveVersionId"])
|
|
2316
|
+
self.assertFalse(row["_body_available"])
|
|
2317
|
+
self.assertEqual(row["_source"], "FlowDefinitionView")
|
|
2318
|
+
self.assertEqual(row["DeveloperName"], "SvcCopilotTmpl__VerifyCode")
|
|
2319
|
+
self.assertEqual(row["NamespacePrefix"], "SvcCopilotTmpl")
|
|
2320
|
+
self.assertEqual(row["_bare_developer_name"], "VerifyCode")
|
|
2321
|
+
self.assertEqual(mock_dq.call_count, 1)
|
|
2322
|
+
|
|
2323
|
+
def test_fallback_skipped_when_tooling_resolves_everything(self):
|
|
2324
|
+
"""All input names resolved by Tooling → FlowDefinitionView is
|
|
2325
|
+
never queried. Guards against unnecessary Data-API calls on the
|
|
2326
|
+
99% of runs where every referenced flow is unmanaged or locally
|
|
2327
|
+
installed."""
|
|
2328
|
+
import fetch_soql # type: ignore
|
|
2329
|
+
real_row = {
|
|
2330
|
+
"Id": "300Uv000000Real",
|
|
2331
|
+
"DeveloperName": "MyFlow",
|
|
2332
|
+
"NamespacePrefix": None,
|
|
2333
|
+
"ActiveVersionId": "301Vf000000Real",
|
|
2334
|
+
}
|
|
2335
|
+
with mock.patch.object(
|
|
2336
|
+
fetch_soql, "tooling_query",
|
|
2337
|
+
return_value={"records": [real_row]},
|
|
2338
|
+
), mock.patch.object(fetch_soql, "data_query") as mock_dq:
|
|
2339
|
+
rows = fetch_soql.fetch_flow_definition_ids_by_names(
|
|
2340
|
+
["MyFlow"],
|
|
2341
|
+
lambda: ("url", "tok"),
|
|
2342
|
+
api_version="v60.0",
|
|
2343
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2344
|
+
)
|
|
2345
|
+
self.assertEqual(len(rows), 1)
|
|
2346
|
+
self.assertEqual(rows[0]["_source"], "FlowDefinition")
|
|
2347
|
+
self.assertTrue(rows[0]["_body_available"])
|
|
2348
|
+
self.assertEqual(mock_dq.call_count, 0)
|
|
2349
|
+
|
|
2350
|
+
def test_mixed_resolution_paths(self):
|
|
2351
|
+
"""Three input names, three distinct fates:
|
|
2352
|
+
1. `ExistingFlow` — unmanaged, resolved by Tooling.
|
|
2353
|
+
2. `SvcCopilotTmpl__VerifyCode` — managed miss on Tooling,
|
|
2354
|
+
resolved by FlowDefinitionView.
|
|
2355
|
+
3. `ghost_ns__GhostFlow` — managed miss on BOTH surfaces.
|
|
2356
|
+
|
|
2357
|
+
Expected: 2 rows total (1 real + 1 view-only), the ghost flow
|
|
2358
|
+
absent from the result set. FlowDefinitionView queried exactly
|
|
2359
|
+
once with both unresolved names in the IN-list.
|
|
2360
|
+
"""
|
|
2361
|
+
import fetch_soql # type: ignore
|
|
2362
|
+
|
|
2363
|
+
real_row = {
|
|
2364
|
+
"Id": "300Uv000000Real",
|
|
2365
|
+
"DeveloperName": "ExistingFlow",
|
|
2366
|
+
"NamespacePrefix": None,
|
|
2367
|
+
"ActiveVersionId": "301Vf000000Real",
|
|
2368
|
+
}
|
|
2369
|
+
view_row = {
|
|
2370
|
+
"DurableId": "SvcCopilotTmpl__VerifyCode",
|
|
2371
|
+
"ApiName": "VerifyCode",
|
|
2372
|
+
"NamespacePrefix": "SvcCopilotTmpl",
|
|
2373
|
+
"ActiveVersionId": "SvcCopilotTmpl__VerifyCode-1",
|
|
2374
|
+
"ManageableState": "installed",
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
# Tooling is called exactly once — the unmanaged query (template
|
|
2378
|
+
# filters NamespacePrefix IS NULL). It matches only ExistingFlow;
|
|
2379
|
+
# the two managed-qualified names return no rows from that
|
|
2380
|
+
# surface and fall through to the view fallback.
|
|
2381
|
+
with mock.patch.object(
|
|
2382
|
+
fetch_soql, "tooling_query",
|
|
2383
|
+
return_value={"records": [real_row]},
|
|
2384
|
+
) as mock_tq, mock.patch.object(
|
|
2385
|
+
fetch_soql, "data_query",
|
|
2386
|
+
return_value={"records": [view_row]},
|
|
2387
|
+
) as mock_dq:
|
|
2388
|
+
rows = fetch_soql.fetch_flow_definition_ids_by_names(
|
|
2389
|
+
[
|
|
2390
|
+
"ExistingFlow",
|
|
2391
|
+
"SvcCopilotTmpl__VerifyCode",
|
|
2392
|
+
"ghost_ns__GhostFlow",
|
|
2393
|
+
],
|
|
2394
|
+
lambda: ("url", "tok"),
|
|
2395
|
+
api_version="v60.0",
|
|
2396
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2397
|
+
)
|
|
2398
|
+
self.assertEqual(len(rows), 2)
|
|
2399
|
+
# Tooling queried exactly once for the full input (no bucketing).
|
|
2400
|
+
self.assertEqual(mock_tq.call_count, 1)
|
|
2401
|
+
# View fallback queried exactly once — no per-name fanout.
|
|
2402
|
+
self.assertEqual(mock_dq.call_count, 1)
|
|
2403
|
+
|
|
2404
|
+
by_name = {r["DeveloperName"]: r for r in rows}
|
|
2405
|
+
# Real Tooling row — source marker explicit.
|
|
2406
|
+
self.assertEqual(by_name["ExistingFlow"]["Id"], "300Uv000000Real")
|
|
2407
|
+
self.assertEqual(by_name["ExistingFlow"]["_source"], "FlowDefinition")
|
|
2408
|
+
self.assertTrue(by_name["ExistingFlow"]["_body_available"])
|
|
2409
|
+
# View-only row — no Id, no active version, marked unavailable.
|
|
2410
|
+
view_result = by_name["SvcCopilotTmpl__VerifyCode"]
|
|
2411
|
+
self.assertIsNone(view_result["Id"])
|
|
2412
|
+
self.assertIsNone(view_result["ActiveVersionId"])
|
|
2413
|
+
self.assertFalse(view_result["_body_available"])
|
|
2414
|
+
self.assertEqual(view_result["_source"], "FlowDefinitionView")
|
|
2415
|
+
# Ghost flow absent.
|
|
2416
|
+
self.assertNotIn("ghost_ns__GhostFlow", by_name)
|
|
2417
|
+
|
|
2418
|
+
|
|
2419
|
+
class FetchPlannerDefinitionChainTests(unittest.TestCase):
|
|
2420
|
+
"""2026-05-05: `fetch_planner_definition(agent, version)` performs a
|
|
2421
|
+
chain-LIKE lookup against GenAiPlannerDefinition. The accretive
|
|
2422
|
+
naming invariant (v1=`<Agent>`, v2=`<Agent>_v2`, v3=
|
|
2423
|
+
`<Agent>_v2_v3`, ...) means the correct planner always matches
|
|
2424
|
+
`<Agent>%\\_vN` for vN>=2 and `<Agent>` exactly for v1. On multi-row
|
|
2425
|
+
matches the resolver picks the row with the shortest DeveloperName.
|
|
2426
|
+
"""
|
|
2427
|
+
|
|
2428
|
+
def _stub_tooling(self, records):
|
|
2429
|
+
"""Patch `fetch_soql.tooling_query` to return a fixed record list."""
|
|
2430
|
+
import fetch_soql # type: ignore
|
|
2431
|
+
return mock.patch.object(
|
|
2432
|
+
fetch_soql, "tooling_query",
|
|
2433
|
+
return_value={"records": records},
|
|
2434
|
+
)
|
|
2435
|
+
|
|
2436
|
+
def test_v1_exact_match(self):
|
|
2437
|
+
import fetch_soql # type: ignore
|
|
2438
|
+
with self._stub_tooling([
|
|
2439
|
+
{"Id": "1VxVF000V1", "DeveloperName": "Inbound_Sales_Agent"},
|
|
2440
|
+
]):
|
|
2441
|
+
row = fetch_soql.fetch_planner_definition(
|
|
2442
|
+
"Inbound_Sales_Agent", None,
|
|
2443
|
+
lambda: ("url", "tok"),
|
|
2444
|
+
api_version="v66.0",
|
|
2445
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2446
|
+
)
|
|
2447
|
+
self.assertIsNotNone(row)
|
|
2448
|
+
self.assertEqual(row["DeveloperName"], "Inbound_Sales_Agent")
|
|
2449
|
+
|
|
2450
|
+
def test_v1_explicit_string(self):
|
|
2451
|
+
import fetch_soql # type: ignore
|
|
2452
|
+
with self._stub_tooling([
|
|
2453
|
+
{"Id": "1VxVF000V1", "DeveloperName": "Inbound_Sales_Agent"},
|
|
2454
|
+
]):
|
|
2455
|
+
row = fetch_soql.fetch_planner_definition(
|
|
2456
|
+
"Inbound_Sales_Agent", "v1",
|
|
2457
|
+
lambda: ("url", "tok"),
|
|
2458
|
+
api_version="v66.0",
|
|
2459
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2460
|
+
)
|
|
2461
|
+
self.assertEqual(row["DeveloperName"], "Inbound_Sales_Agent")
|
|
2462
|
+
|
|
2463
|
+
def test_v2_single_match(self):
|
|
2464
|
+
import fetch_soql # type: ignore
|
|
2465
|
+
with self._stub_tooling([
|
|
2466
|
+
{"Id": "1VxVF000V2", "DeveloperName": "Inbound_Sales_Agent_v2"},
|
|
2467
|
+
]):
|
|
2468
|
+
row = fetch_soql.fetch_planner_definition(
|
|
2469
|
+
"Inbound_Sales_Agent", "v2",
|
|
2470
|
+
lambda: ("url", "tok"),
|
|
2471
|
+
api_version="v66.0",
|
|
2472
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2473
|
+
)
|
|
2474
|
+
self.assertEqual(row["DeveloperName"], "Inbound_Sales_Agent_v2")
|
|
2475
|
+
|
|
2476
|
+
def test_v2_multi_row_shortest_wins(self):
|
|
2477
|
+
"""LIKE `<Agent>%\\_v2` can match both `<Agent>_v2` and a deeper
|
|
2478
|
+
chain like `<Agent>_foo_v2` (rare but possible). Shortest
|
|
2479
|
+
DeveloperName wins — the canonical row carries no extra segment."""
|
|
2480
|
+
import fetch_soql # type: ignore
|
|
2481
|
+
with self._stub_tooling([
|
|
2482
|
+
{"Id": "1VxVF000DEEPER",
|
|
2483
|
+
"DeveloperName": "Inbound_Sales_Agent_foo_v2"},
|
|
2484
|
+
{"Id": "1VxVF000V2",
|
|
2485
|
+
"DeveloperName": "Inbound_Sales_Agent_v2"},
|
|
2486
|
+
]):
|
|
2487
|
+
row = fetch_soql.fetch_planner_definition(
|
|
2488
|
+
"Inbound_Sales_Agent", "v2",
|
|
2489
|
+
lambda: ("url", "tok"),
|
|
2490
|
+
api_version="v66.0",
|
|
2491
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2492
|
+
)
|
|
2493
|
+
self.assertEqual(row["DeveloperName"], "Inbound_Sales_Agent_v2")
|
|
2494
|
+
|
|
2495
|
+
def test_zero_rows_returns_none(self):
|
|
2496
|
+
import fetch_soql # type: ignore
|
|
2497
|
+
with self._stub_tooling([]):
|
|
2498
|
+
row = fetch_soql.fetch_planner_definition(
|
|
2499
|
+
"NoSuchAgent", "v3",
|
|
2500
|
+
lambda: ("url", "tok"),
|
|
2501
|
+
api_version="v66.0",
|
|
2502
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2503
|
+
)
|
|
2504
|
+
self.assertIsNone(row)
|
|
2505
|
+
|
|
2506
|
+
def test_chain_like_pattern_passed_to_soql_for_v5(self):
|
|
2507
|
+
"""The SOQL body that reaches `tooling_query` contains the chain
|
|
2508
|
+
LIKE pattern literally. Verify AGENT_NAME + VERSION are rendered
|
|
2509
|
+
through the template with the `%\\_` escape in between.
|
|
2510
|
+
"""
|
|
2511
|
+
import fetch_soql # type: ignore
|
|
2512
|
+
captured: dict = {}
|
|
2513
|
+
|
|
2514
|
+
def fake_tooling(creds_provider, soql, *, api_version, on_401_refresh):
|
|
2515
|
+
captured["soql"] = soql
|
|
2516
|
+
return {"records": []}
|
|
2517
|
+
|
|
2518
|
+
with mock.patch.object(fetch_soql, "tooling_query",
|
|
2519
|
+
side_effect=fake_tooling):
|
|
2520
|
+
fetch_soql.fetch_planner_definition(
|
|
2521
|
+
"MyAgent", "v5",
|
|
2522
|
+
lambda: ("url", "tok"),
|
|
2523
|
+
api_version="v66.0",
|
|
2524
|
+
on_401_refresh=lambda: ("url", "tok"),
|
|
2525
|
+
)
|
|
2526
|
+
self.assertIn("LIKE 'MyAgent%\\_v5'", captured["soql"])
|
|
2527
|
+
|
|
2528
|
+
|
|
2529
|
+
class SwapDirAtomicCoTenancyTests(unittest.TestCase):
|
|
2530
|
+
"""`_swap_dir_atomic` preserves sibling content in `target`. The prior
|
|
2531
|
+
whole-directory `os.replace` wiped any co-tenant subdirs that another
|
|
2532
|
+
caller may have written into the same `<agent>__<ver>/` directory."""
|
|
2533
|
+
|
|
2534
|
+
def test_preserves_sibling_session_dirs(self) -> None:
|
|
2535
|
+
# Simulate co-tenancy: target dir already has a sibling subdir
|
|
2536
|
+
# + a bare file written by some other caller.
|
|
2537
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2538
|
+
tmp_p = Path(tmp)
|
|
2539
|
+
target = tmp_p / "agent__v1"
|
|
2540
|
+
target.mkdir()
|
|
2541
|
+
(target / "sibling-data").mkdir()
|
|
2542
|
+
(target / "sibling-data" / "payload.json").write_text(
|
|
2543
|
+
"from-other-caller"
|
|
2544
|
+
)
|
|
2545
|
+
(target / "_sessions").mkdir()
|
|
2546
|
+
(target / "_sessions" / "marker.link").write_text(
|
|
2547
|
+
"../agent__v1/sibling-data"
|
|
2548
|
+
)
|
|
2549
|
+
|
|
2550
|
+
# Architecture's own previous output, about to be overwritten.
|
|
2551
|
+
(target / "old_tree.json").write_text("old")
|
|
2552
|
+
|
|
2553
|
+
# Staging dir — what architecture wants to write.
|
|
2554
|
+
staging = tmp_p / ".agent__v1.staging.123"
|
|
2555
|
+
staging.mkdir()
|
|
2556
|
+
(staging / "agent_v1_metadata_tree.json").write_text("new-tree")
|
|
2557
|
+
(staging / "last_built_at.txt").write_text("2026-05-05T12:00:00Z\n")
|
|
2558
|
+
|
|
2559
|
+
main._swap_dir_atomic(target, staging)
|
|
2560
|
+
|
|
2561
|
+
# Sibling content survives — the whole point of the fix.
|
|
2562
|
+
self.assertTrue(
|
|
2563
|
+
(target / "sibling-data" / "payload.json").is_file()
|
|
2564
|
+
)
|
|
2565
|
+
self.assertEqual(
|
|
2566
|
+
(target / "sibling-data" / "payload.json").read_text(),
|
|
2567
|
+
"from-other-caller",
|
|
2568
|
+
)
|
|
2569
|
+
self.assertTrue((target / "_sessions" / "marker.link").is_file())
|
|
2570
|
+
|
|
2571
|
+
# Architecture's new files landed.
|
|
2572
|
+
self.assertEqual(
|
|
2573
|
+
(target / "agent_v1_metadata_tree.json").read_text(), "new-tree"
|
|
2574
|
+
)
|
|
2575
|
+
self.assertTrue((target / "last_built_at.txt").is_file())
|
|
2576
|
+
|
|
2577
|
+
# Old file that wasn't in staging stays untouched.
|
|
2578
|
+
self.assertTrue((target / "old_tree.json").is_file())
|
|
2579
|
+
self.assertEqual((target / "old_tree.json").read_text(), "old")
|
|
2580
|
+
|
|
2581
|
+
# Staging dir cleaned up.
|
|
2582
|
+
self.assertFalse(staging.exists())
|
|
2583
|
+
|
|
2584
|
+
def test_overwrites_own_files_cleanly(self) -> None:
|
|
2585
|
+
"""Same filename in both target and staging → staging content wins."""
|
|
2586
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2587
|
+
tmp_p = Path(tmp)
|
|
2588
|
+
target = tmp_p / "agent__v1"
|
|
2589
|
+
target.mkdir()
|
|
2590
|
+
(target / "tree.json").write_text("old-content")
|
|
2591
|
+
|
|
2592
|
+
staging = tmp_p / ".agent__v1.staging.123"
|
|
2593
|
+
staging.mkdir()
|
|
2594
|
+
(staging / "tree.json").write_text("new-content")
|
|
2595
|
+
|
|
2596
|
+
main._swap_dir_atomic(target, staging)
|
|
2597
|
+
|
|
2598
|
+
self.assertEqual(
|
|
2599
|
+
(target / "tree.json").read_text(), "new-content"
|
|
2600
|
+
)
|
|
2601
|
+
|
|
2602
|
+
def test_overwrites_when_target_entry_is_dir(self) -> None:
|
|
2603
|
+
"""If the old target entry is a directory and the new staging
|
|
2604
|
+
entry is a file (or vice versa), replace cleans up the old kind
|
|
2605
|
+
before os.replace lands the new one."""
|
|
2606
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2607
|
+
tmp_p = Path(tmp)
|
|
2608
|
+
target = tmp_p / "agent__v1"
|
|
2609
|
+
target.mkdir()
|
|
2610
|
+
# Old entry is a directory with nested content.
|
|
2611
|
+
(target / "payload").mkdir()
|
|
2612
|
+
(target / "payload" / "nested.txt").write_text("deep")
|
|
2613
|
+
|
|
2614
|
+
staging = tmp_p / ".agent__v1.staging.123"
|
|
2615
|
+
staging.mkdir()
|
|
2616
|
+
# New entry with the same name is a plain file.
|
|
2617
|
+
(staging / "payload").write_text("now-a-file")
|
|
2618
|
+
|
|
2619
|
+
main._swap_dir_atomic(target, staging)
|
|
2620
|
+
|
|
2621
|
+
self.assertTrue((target / "payload").is_file())
|
|
2622
|
+
self.assertEqual(
|
|
2623
|
+
(target / "payload").read_text(), "now-a-file"
|
|
2624
|
+
)
|
|
2625
|
+
|
|
2626
|
+
def test_missing_staging_raises(self) -> None:
|
|
2627
|
+
"""Pre-existing precondition: staging must exist, or we raise."""
|
|
2628
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2629
|
+
tmp_p = Path(tmp)
|
|
2630
|
+
target = tmp_p / "agent__v1"
|
|
2631
|
+
target.mkdir()
|
|
2632
|
+
staging = tmp_p / ".agent__v1.staging.does-not-exist"
|
|
2633
|
+
with self.assertRaises(OSError):
|
|
2634
|
+
main._swap_dir_atomic(target, staging)
|
|
2635
|
+
|
|
2636
|
+
def test_run_finalize_preserves_session_subdir_across_reruns(self) -> None:
|
|
2637
|
+
"""End-to-end via `_run_finalize`: after a first successful run
|
|
2638
|
+
seeds a co-tenant session dir, a second run must not wipe it.
|
|
2639
|
+
Covers the production path — the bug the user reported."""
|
|
2640
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
2641
|
+
tmp_p = Path(tmp)
|
|
2642
|
+
work_dir = tmp_p / "work"
|
|
2643
|
+
work_dir.mkdir()
|
|
2644
|
+
data_dir = tmp_p / "data" / "A__v1"
|
|
2645
|
+
cache_dir = tmp_p / "cache" / "A__v1"
|
|
2646
|
+
|
|
2647
|
+
tree = {
|
|
2648
|
+
"_schema_version": "3.0",
|
|
2649
|
+
"agent": {"api_name": "A", "version": "v1"},
|
|
2650
|
+
"root": {"kind": "BOT_DEFINITION", "api_name": "A",
|
|
2651
|
+
"children": []},
|
|
2652
|
+
"node_count": 1, "depth": 0,
|
|
2653
|
+
"_kind_counts": {"BOT_DEFINITION": 1},
|
|
2654
|
+
"_pending_fetches": {k: [] for k in (
|
|
2655
|
+
"FLOW", "APEX", "PROMPT_TEMPLATE", "STANDARD_ACTION",
|
|
2656
|
+
)},
|
|
2657
|
+
"_unresolved": [],
|
|
2658
|
+
}
|
|
2659
|
+
# First run — populate data_dir.
|
|
2660
|
+
main._run_finalize(
|
|
2661
|
+
data_dir, cache_dir, dict(tree), work_dir,
|
|
2662
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
2663
|
+
)
|
|
2664
|
+
# Simulate a co-tenant dropping content alongside.
|
|
2665
|
+
sibling_dir = data_dir / "sibling-payload"
|
|
2666
|
+
sibling_dir.mkdir()
|
|
2667
|
+
(sibling_dir / "payload.json").write_text("cotenant-data")
|
|
2668
|
+
|
|
2669
|
+
# Second run — the original bug: this would wipe the sibling dir.
|
|
2670
|
+
main._run_finalize(
|
|
2671
|
+
data_dir, cache_dir, dict(tree), work_dir,
|
|
2672
|
+
agent_api_name="A", agent_version="v1", planner_name="A",
|
|
2673
|
+
)
|
|
2674
|
+
|
|
2675
|
+
# Sibling dir and its contents must survive.
|
|
2676
|
+
self.assertTrue(sibling_dir.is_dir())
|
|
2677
|
+
self.assertTrue((sibling_dir / "payload.json").is_file())
|
|
2678
|
+
self.assertEqual(
|
|
2679
|
+
(sibling_dir / "payload.json").read_text(),
|
|
2680
|
+
"cotenant-data",
|
|
2681
|
+
)
|
|
2682
|
+
# Architecture's own tree is still present (re-written).
|
|
2683
|
+
self.assertTrue((data_dir / "A_v1_metadata_tree.json").is_file())
|
|
2684
|
+
|
|
2685
|
+
|
|
2686
|
+
# ---------------------------------------------------------------------------
|
|
2687
|
+
# Bug 1 fix (2026-05-05): GenAiPromptTemplate is NOT SOQL-queryable. Id →
|
|
2688
|
+
# DeveloperName resolution runs through `sf org list metadata` (Metadata
|
|
2689
|
+
# API) via the new `list_prompt_template_metadata` helper.
|
|
2690
|
+
# ---------------------------------------------------------------------------
|
|
2691
|
+
|
|
2692
|
+
|
|
2693
|
+
class ListPromptTemplateMetadataTests(unittest.TestCase):
|
|
2694
|
+
"""Unit tests for `metadata_listing.list_prompt_template_metadata` —
|
|
2695
|
+
thin wrapper over `run_sf("list_metadata_genaiprompttemplate", ...)`.
|
|
2696
|
+
|
|
2697
|
+
The shape we care about is produced by the sf CLI:
|
|
2698
|
+
{"status": 0, "result": [{"id": "0hfUv...", "fullName": "Foo", ...}]}
|
|
2699
|
+
Defensive returns on malformed result (None / wrong type) keep the
|
|
2700
|
+
failure mode quiet — callers already tolerate empty lists.
|
|
2701
|
+
"""
|
|
2702
|
+
|
|
2703
|
+
def test_happy_path_returns_result_rows(self):
|
|
2704
|
+
import metadata_listing # type: ignore
|
|
2705
|
+
payload = {
|
|
2706
|
+
"status": 0,
|
|
2707
|
+
"result": [
|
|
2708
|
+
{"id": "0hfUv0000021mCjIAI", "fullName": "My_Prompt",
|
|
2709
|
+
"type": "GenAiPromptTemplate"},
|
|
2710
|
+
{"id": "0hfUv0000021mOtherAAA", "fullName": "Other_Prompt",
|
|
2711
|
+
"type": "GenAiPromptTemplate"},
|
|
2712
|
+
],
|
|
2713
|
+
}
|
|
2714
|
+
with mock.patch.object(metadata_listing, "run_sf", return_value=payload):
|
|
2715
|
+
rows = metadata_listing.list_prompt_template_metadata("test-org")
|
|
2716
|
+
self.assertEqual(rows, payload["result"])
|
|
2717
|
+
|
|
2718
|
+
def test_empty_result_returns_empty_list(self):
|
|
2719
|
+
import metadata_listing # type: ignore
|
|
2720
|
+
with mock.patch.object(
|
|
2721
|
+
metadata_listing, "run_sf",
|
|
2722
|
+
return_value={"status": 0, "result": []},
|
|
2723
|
+
):
|
|
2724
|
+
rows = metadata_listing.list_prompt_template_metadata("test-org")
|
|
2725
|
+
self.assertEqual(rows, [])
|
|
2726
|
+
|
|
2727
|
+
def test_malformed_result_returns_empty_list(self):
|
|
2728
|
+
"""Defensive: if sf CLI's `result` key is not a list (e.g. None
|
|
2729
|
+
on some error paths that still exit 0), we degrade to []."""
|
|
2730
|
+
import metadata_listing # type: ignore
|
|
2731
|
+
with mock.patch.object(
|
|
2732
|
+
metadata_listing, "run_sf",
|
|
2733
|
+
return_value={"status": 0, "result": None},
|
|
2734
|
+
):
|
|
2735
|
+
rows = metadata_listing.list_prompt_template_metadata("test-org")
|
|
2736
|
+
self.assertEqual(rows, [])
|
|
2737
|
+
|
|
2738
|
+
|
|
2739
|
+
class FetchWaveBPromptTemplateMetadataWiringTests(unittest.TestCase):
|
|
2740
|
+
"""Bug 1 fix (2026-05-05): `_fetch_wave_b_by_names` invokes
|
|
2741
|
+
`list_prompt_template_metadata` (Metadata API listing), then filters +
|
|
2742
|
+
reshapes to the {Id, DeveloperName} shape the downstream pipeline
|
|
2743
|
+
expects. Verify the filter + reshape contract — only the requested
|
|
2744
|
+
Ids come back, keyed as the pipeline's existing prompt_template_id_rows
|
|
2745
|
+
shape.
|
|
2746
|
+
"""
|
|
2747
|
+
|
|
2748
|
+
def test_listmetadata_rows_filtered_and_reshaped(self):
|
|
2749
|
+
with mock.patch.object(
|
|
2750
|
+
main, "list_prompt_template_metadata",
|
|
2751
|
+
return_value=[
|
|
2752
|
+
{"id": "0hfAAA", "fullName": "TplA",
|
|
2753
|
+
"type": "GenAiPromptTemplate"},
|
|
2754
|
+
{"id": "0hfBBB", "fullName": "TplB",
|
|
2755
|
+
"type": "GenAiPromptTemplate"},
|
|
2756
|
+
],
|
|
2757
|
+
):
|
|
2758
|
+
with mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]), \
|
|
2759
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]), \
|
|
2760
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]), \
|
|
2761
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]):
|
|
2762
|
+
out = main._fetch_wave_b_by_names(
|
|
2763
|
+
apex_names=[],
|
|
2764
|
+
apex_ids=[],
|
|
2765
|
+
flow_names=[],
|
|
2766
|
+
flow_ids=[],
|
|
2767
|
+
prompt_template_ids=["0hfAAA"],
|
|
2768
|
+
creds_provider=lambda: ("url", "tok"),
|
|
2769
|
+
refresh_fn=lambda: ("url", "tok"),
|
|
2770
|
+
api_version="v60.0",
|
|
2771
|
+
org_alias="test-org",
|
|
2772
|
+
parallelism=2,
|
|
2773
|
+
)
|
|
2774
|
+
# Only the requested Id survives (0hfAAA); 0hfBBB is filtered out.
|
|
2775
|
+
# The shape matches the old SOQL contract: {Id, DeveloperName}.
|
|
2776
|
+
self.assertEqual(
|
|
2777
|
+
out["prompt_template_id_rows"],
|
|
2778
|
+
[{"Id": "0hfAAA", "DeveloperName": "TplA"}],
|
|
2779
|
+
)
|
|
2780
|
+
|
|
2781
|
+
def test_listmetadata_failure_non_fatal(self):
|
|
2782
|
+
"""SfCliError from the Metadata listing is caught and surfaced via
|
|
2783
|
+
the unresolved channel; the run continues with an empty rowset."""
|
|
2784
|
+
from sf_cli import SfCliError # type: ignore
|
|
2785
|
+
with mock.patch.object(
|
|
2786
|
+
main, "list_prompt_template_metadata",
|
|
2787
|
+
side_effect=SfCliError("metadata-listing-exploded"),
|
|
2788
|
+
):
|
|
2789
|
+
with mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]), \
|
|
2790
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]), \
|
|
2791
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]), \
|
|
2792
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]):
|
|
2793
|
+
out = main._fetch_wave_b_by_names(
|
|
2794
|
+
apex_names=[],
|
|
2795
|
+
apex_ids=[],
|
|
2796
|
+
flow_names=[],
|
|
2797
|
+
flow_ids=[],
|
|
2798
|
+
prompt_template_ids=["0hfAAA"],
|
|
2799
|
+
creds_provider=lambda: ("url", "tok"),
|
|
2800
|
+
refresh_fn=lambda: ("url", "tok"),
|
|
2801
|
+
api_version="v60.0",
|
|
2802
|
+
org_alias="test-org",
|
|
2803
|
+
parallelism=2,
|
|
2804
|
+
)
|
|
2805
|
+
self.assertEqual(out["prompt_template_id_rows"], [])
|
|
2806
|
+
reasons = [u.get("reason") or "" for u in out["unresolved"]]
|
|
2807
|
+
self.assertTrue(
|
|
2808
|
+
any("prompt-template-listmetadata-failed" in r for r in reasons),
|
|
2809
|
+
f"expected listmetadata-failed in unresolved; got {reasons}",
|
|
2810
|
+
)
|
|
2811
|
+
|
|
2812
|
+
|
|
2813
|
+
class RetrievePromptTemplatesTests(unittest.TestCase):
|
|
2814
|
+
"""Gap C (2026-05-05): unit tests for
|
|
2815
|
+
`metadata_listing.retrieve_prompt_templates` — the sf CLI wrapper
|
|
2816
|
+
that retrieves GenAiPromptTemplate bodies via
|
|
2817
|
+
`sf project retrieve start --metadata GenAiPromptTemplate:...`.
|
|
2818
|
+
|
|
2819
|
+
The helper:
|
|
2820
|
+
1. Short-circuits on empty input (no sf call).
|
|
2821
|
+
2. Parses `unpackaged.zip` from the retrieve dir via stdlib
|
|
2822
|
+
`zipfile` + `xml.etree.ElementTree`.
|
|
2823
|
+
3. Extracts developerName/masterLabel/activeVersionIdentifier/
|
|
2824
|
+
templateVersions[*].content/inputs[*].
|
|
2825
|
+
4. Returns `{}` on SfCliError (non-fatal — main.py's call site
|
|
2826
|
+
logs an `_unresolved[]` entry).
|
|
2827
|
+
5. Skips files whose XML fails to parse; sibling templates still
|
|
2828
|
+
surface.
|
|
2829
|
+
"""
|
|
2830
|
+
|
|
2831
|
+
def _run_retrieve_writes_zip(self, files: dict):
|
|
2832
|
+
"""Build a mock `_run_retrieve` side_effect that writes an
|
|
2833
|
+
unpackaged.zip into the retrieve dir as the real CLI would.
|
|
2834
|
+
|
|
2835
|
+
`files = {inner_path: xml_bytes}`. `retrieve_prompt_templates`
|
|
2836
|
+
wipes the retrieve dir before invoking the subprocess, so the zip
|
|
2837
|
+
MUST be created by the mock (the retrieve dir is always the
|
|
2838
|
+
`--target-metadata-dir` argv element)."""
|
|
2839
|
+
import zipfile
|
|
2840
|
+
|
|
2841
|
+
def _side_effect(argv, timeout):
|
|
2842
|
+
target_dir = Path(argv[argv.index("--target-metadata-dir") + 1])
|
|
2843
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
2844
|
+
zip_path = target_dir / "unpackaged.zip"
|
|
2845
|
+
with zipfile.ZipFile(zip_path, "w") as zf:
|
|
2846
|
+
for inner, xml_bytes in files.items():
|
|
2847
|
+
zf.writestr(inner, xml_bytes)
|
|
2848
|
+
return subprocess.CompletedProcess(
|
|
2849
|
+
argv, returncode=0, stdout='{"status":0,"result":{}}', stderr="",
|
|
2850
|
+
)
|
|
2851
|
+
|
|
2852
|
+
return _side_effect
|
|
2853
|
+
|
|
2854
|
+
def test_empty_input_short_circuits_without_sf_call(self):
|
|
2855
|
+
import metadata_listing # type: ignore
|
|
2856
|
+
with mock.patch.object(metadata_listing, "_run_retrieve") as mrun, \
|
|
2857
|
+
tempfile.TemporaryDirectory() as d:
|
|
2858
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
2859
|
+
"org-alias", [], Path(d),
|
|
2860
|
+
)
|
|
2861
|
+
self.assertEqual(result, {})
|
|
2862
|
+
mrun.assert_not_called()
|
|
2863
|
+
|
|
2864
|
+
def test_happy_path_single_template(self):
|
|
2865
|
+
import metadata_listing # type: ignore
|
|
2866
|
+
xml = (
|
|
2867
|
+
b'<?xml version="1.0" encoding="UTF-8"?>'
|
|
2868
|
+
b'<GenAiPromptTemplate xmlns="http://soap.sforce.com/2006/04/metadata">'
|
|
2869
|
+
b'<developerName>My_Prompt</developerName>'
|
|
2870
|
+
b'<masterLabel>My Prompt</masterLabel>'
|
|
2871
|
+
b'<activeVersionIdentifier>v1</activeVersionIdentifier>'
|
|
2872
|
+
b'<templateVersions>'
|
|
2873
|
+
b'<versionIdentifier>v1</versionIdentifier>'
|
|
2874
|
+
b'<content># ROLE\nHello {{$Input:Query}}</content>'
|
|
2875
|
+
b'<inputs><apiName>Query</apiName><dataType>String</dataType></inputs>'
|
|
2876
|
+
b'</templateVersions>'
|
|
2877
|
+
b'</GenAiPromptTemplate>'
|
|
2878
|
+
)
|
|
2879
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2880
|
+
tmp = Path(d)
|
|
2881
|
+
side_effect = self._run_retrieve_writes_zip({
|
|
2882
|
+
"unpackaged/genAiPromptTemplates/My_Prompt.genAiPromptTemplate": xml,
|
|
2883
|
+
"unpackaged/package.xml": b"<Package/>",
|
|
2884
|
+
})
|
|
2885
|
+
with mock.patch.object(
|
|
2886
|
+
metadata_listing, "_run_retrieve", side_effect=side_effect,
|
|
2887
|
+
):
|
|
2888
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
2889
|
+
"org-alias", ["My_Prompt"], tmp,
|
|
2890
|
+
)
|
|
2891
|
+
self.assertIn("My_Prompt", result)
|
|
2892
|
+
body = result["My_Prompt"]
|
|
2893
|
+
self.assertEqual(body["developerName"], "My_Prompt")
|
|
2894
|
+
self.assertEqual(body["masterLabel"], "My Prompt")
|
|
2895
|
+
self.assertEqual(body["activeVersionIdentifier"], "v1")
|
|
2896
|
+
self.assertEqual(body["content"], "# ROLE\nHello {{$Input:Query}}")
|
|
2897
|
+
self.assertEqual(
|
|
2898
|
+
body["inputs"], [{"name": "Query", "dataType": "String"}],
|
|
2899
|
+
)
|
|
2900
|
+
|
|
2901
|
+
def test_sf_cli_error_returns_empty_dict(self):
|
|
2902
|
+
"""Non-zero exit without auth-pattern stderr is swallowed as
|
|
2903
|
+
non-fatal — caller gets an empty dict."""
|
|
2904
|
+
import metadata_listing # type: ignore
|
|
2905
|
+
failure = subprocess.CompletedProcess(
|
|
2906
|
+
args=[], returncode=1, stdout="", stderr="Error: retrieve blew up",
|
|
2907
|
+
)
|
|
2908
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2909
|
+
with mock.patch.object(
|
|
2910
|
+
metadata_listing, "_run_retrieve", return_value=failure,
|
|
2911
|
+
):
|
|
2912
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
2913
|
+
"org-alias", ["Foo"], Path(d),
|
|
2914
|
+
)
|
|
2915
|
+
self.assertEqual(result, {})
|
|
2916
|
+
|
|
2917
|
+
def test_auth_required_reraises(self):
|
|
2918
|
+
"""Non-zero exit WITH auth-pattern stderr raises AuthRequired."""
|
|
2919
|
+
import metadata_listing # type: ignore
|
|
2920
|
+
from sf_cli import AuthRequired # type: ignore
|
|
2921
|
+
failure = subprocess.CompletedProcess(
|
|
2922
|
+
args=[], returncode=1, stdout="",
|
|
2923
|
+
stderr="Error: NoOrgAuthenticationError — login required",
|
|
2924
|
+
)
|
|
2925
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2926
|
+
with mock.patch.object(
|
|
2927
|
+
metadata_listing, "_run_retrieve", return_value=failure,
|
|
2928
|
+
):
|
|
2929
|
+
with self.assertRaises(AuthRequired):
|
|
2930
|
+
metadata_listing.retrieve_prompt_templates(
|
|
2931
|
+
"org-alias", ["Foo"], Path(d),
|
|
2932
|
+
)
|
|
2933
|
+
|
|
2934
|
+
def test_missing_zip_returns_empty_dict(self):
|
|
2935
|
+
import metadata_listing # type: ignore
|
|
2936
|
+
# _run_retrieve succeeds but leaves no unpackaged.zip on disk.
|
|
2937
|
+
success_no_zip = subprocess.CompletedProcess(
|
|
2938
|
+
args=[], returncode=0, stdout='{"status":0,"result":{}}', stderr="",
|
|
2939
|
+
)
|
|
2940
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2941
|
+
with mock.patch.object(
|
|
2942
|
+
metadata_listing, "_run_retrieve", return_value=success_no_zip,
|
|
2943
|
+
):
|
|
2944
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
2945
|
+
"org-alias", ["Foo"], Path(d),
|
|
2946
|
+
)
|
|
2947
|
+
self.assertEqual(result, {})
|
|
2948
|
+
|
|
2949
|
+
def test_multi_version_picks_active(self):
|
|
2950
|
+
import metadata_listing # type: ignore
|
|
2951
|
+
xml = (
|
|
2952
|
+
b'<?xml version="1.0" encoding="UTF-8"?>'
|
|
2953
|
+
b'<GenAiPromptTemplate xmlns="http://soap.sforce.com/2006/04/metadata">'
|
|
2954
|
+
b'<developerName>Versioned</developerName>'
|
|
2955
|
+
b'<activeVersionIdentifier>v2</activeVersionIdentifier>'
|
|
2956
|
+
b'<templateVersions>'
|
|
2957
|
+
b'<versionIdentifier>v1</versionIdentifier>'
|
|
2958
|
+
b'<content>OLD</content>'
|
|
2959
|
+
b'</templateVersions>'
|
|
2960
|
+
b'<templateVersions>'
|
|
2961
|
+
b'<versionIdentifier>v2</versionIdentifier>'
|
|
2962
|
+
b'<content>ACTIVE</content>'
|
|
2963
|
+
b'</templateVersions>'
|
|
2964
|
+
b'<templateVersions>'
|
|
2965
|
+
b'<versionIdentifier>v3</versionIdentifier>'
|
|
2966
|
+
b'<content>DRAFT</content>'
|
|
2967
|
+
b'</templateVersions>'
|
|
2968
|
+
b'</GenAiPromptTemplate>'
|
|
2969
|
+
)
|
|
2970
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2971
|
+
tmp = Path(d)
|
|
2972
|
+
side_effect = self._run_retrieve_writes_zip({
|
|
2973
|
+
"unpackaged/genAiPromptTemplates/Versioned.genAiPromptTemplate": xml,
|
|
2974
|
+
})
|
|
2975
|
+
with mock.patch.object(
|
|
2976
|
+
metadata_listing, "_run_retrieve", side_effect=side_effect,
|
|
2977
|
+
):
|
|
2978
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
2979
|
+
"org-alias", ["Versioned"], tmp,
|
|
2980
|
+
)
|
|
2981
|
+
self.assertEqual(result["Versioned"]["content"], "ACTIVE")
|
|
2982
|
+
|
|
2983
|
+
def test_template_with_no_inputs(self):
|
|
2984
|
+
import metadata_listing # type: ignore
|
|
2985
|
+
xml = (
|
|
2986
|
+
b'<?xml version="1.0" encoding="UTF-8"?>'
|
|
2987
|
+
b'<GenAiPromptTemplate xmlns="http://soap.sforce.com/2006/04/metadata">'
|
|
2988
|
+
b'<developerName>NoInputs</developerName>'
|
|
2989
|
+
b'<activeVersionIdentifier>v1</activeVersionIdentifier>'
|
|
2990
|
+
b'<templateVersions>'
|
|
2991
|
+
b'<versionIdentifier>v1</versionIdentifier>'
|
|
2992
|
+
b'<content>Prompt body</content>'
|
|
2993
|
+
b'</templateVersions>'
|
|
2994
|
+
b'</GenAiPromptTemplate>'
|
|
2995
|
+
)
|
|
2996
|
+
with tempfile.TemporaryDirectory() as d:
|
|
2997
|
+
tmp = Path(d)
|
|
2998
|
+
side_effect = self._run_retrieve_writes_zip({
|
|
2999
|
+
"unpackaged/genAiPromptTemplates/NoInputs.genAiPromptTemplate": xml,
|
|
3000
|
+
})
|
|
3001
|
+
with mock.patch.object(
|
|
3002
|
+
metadata_listing, "_run_retrieve", side_effect=side_effect,
|
|
3003
|
+
):
|
|
3004
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
3005
|
+
"org-alias", ["NoInputs"], tmp,
|
|
3006
|
+
)
|
|
3007
|
+
self.assertEqual(result["NoInputs"]["inputs"], [])
|
|
3008
|
+
|
|
3009
|
+
def test_xml_parse_failure_skips_file_continues(self):
|
|
3010
|
+
"""Malformed XML on one template must not prevent sibling
|
|
3011
|
+
templates from surfacing."""
|
|
3012
|
+
import metadata_listing # type: ignore
|
|
3013
|
+
good_xml = (
|
|
3014
|
+
b'<?xml version="1.0" encoding="UTF-8"?>'
|
|
3015
|
+
b'<GenAiPromptTemplate xmlns="http://soap.sforce.com/2006/04/metadata">'
|
|
3016
|
+
b'<developerName>GoodTpl</developerName>'
|
|
3017
|
+
b'<activeVersionIdentifier>v1</activeVersionIdentifier>'
|
|
3018
|
+
b'<templateVersions>'
|
|
3019
|
+
b'<versionIdentifier>v1</versionIdentifier>'
|
|
3020
|
+
b'<content>Fine</content>'
|
|
3021
|
+
b'</templateVersions>'
|
|
3022
|
+
b'</GenAiPromptTemplate>'
|
|
3023
|
+
)
|
|
3024
|
+
broken_xml = b"<not valid xml"
|
|
3025
|
+
with tempfile.TemporaryDirectory() as d:
|
|
3026
|
+
tmp = Path(d)
|
|
3027
|
+
side_effect = self._run_retrieve_writes_zip({
|
|
3028
|
+
"unpackaged/genAiPromptTemplates/GoodTpl.genAiPromptTemplate": good_xml,
|
|
3029
|
+
"unpackaged/genAiPromptTemplates/Broken.genAiPromptTemplate": broken_xml,
|
|
3030
|
+
})
|
|
3031
|
+
with mock.patch.object(
|
|
3032
|
+
metadata_listing, "_run_retrieve", side_effect=side_effect,
|
|
3033
|
+
):
|
|
3034
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
3035
|
+
"org-alias", ["GoodTpl", "Broken"], tmp,
|
|
3036
|
+
)
|
|
3037
|
+
self.assertIn("GoodTpl", result)
|
|
3038
|
+
self.assertNotIn("Broken", result)
|
|
3039
|
+
|
|
3040
|
+
def test_stale_retrieve_dir_contents_wiped(self):
|
|
3041
|
+
"""A prior invocation's `unpackaged.zip` must not be trusted if
|
|
3042
|
+
this run's sf call fails before writing a new one."""
|
|
3043
|
+
import metadata_listing # type: ignore
|
|
3044
|
+
failure = subprocess.CompletedProcess(
|
|
3045
|
+
args=[], returncode=1, stdout="", stderr="Error: boom",
|
|
3046
|
+
)
|
|
3047
|
+
with tempfile.TemporaryDirectory() as d:
|
|
3048
|
+
tmp = Path(d)
|
|
3049
|
+
# Plant a stale zip pretending a prior run left it.
|
|
3050
|
+
stale = tmp / "prompt_template_retrieve"
|
|
3051
|
+
stale.mkdir(parents=True, exist_ok=True)
|
|
3052
|
+
(stale / "unpackaged.zip").write_bytes(b"stale")
|
|
3053
|
+
with mock.patch.object(
|
|
3054
|
+
metadata_listing, "_run_retrieve", return_value=failure,
|
|
3055
|
+
):
|
|
3056
|
+
result = metadata_listing.retrieve_prompt_templates(
|
|
3057
|
+
"org-alias", ["Foo"], tmp,
|
|
3058
|
+
)
|
|
3059
|
+
self.assertEqual(result, {})
|
|
3060
|
+
# Stale file should have been nuked before the sf call.
|
|
3061
|
+
self.assertFalse((stale / "unpackaged.zip").exists())
|
|
3062
|
+
|
|
3063
|
+
def test_retrieve_builds_one_metadata_flag_per_name(self):
|
|
3064
|
+
"""Live proof (2026-05-05): `sf project retrieve start` treats a
|
|
3065
|
+
comma-joined `--metadata TypeA:A,TypeA:B` as ONE malformed member
|
|
3066
|
+
name and silently produces a package-xml-only zip. The fix is to
|
|
3067
|
+
repeat `--metadata` once per template. Lock that shape in."""
|
|
3068
|
+
import metadata_listing # type: ignore
|
|
3069
|
+
captured_argv: list[list[str]] = []
|
|
3070
|
+
|
|
3071
|
+
def _capture(argv, timeout):
|
|
3072
|
+
captured_argv.append(list(argv))
|
|
3073
|
+
return subprocess.CompletedProcess(
|
|
3074
|
+
argv, returncode=0,
|
|
3075
|
+
stdout='{"status":0,"result":{}}', stderr="",
|
|
3076
|
+
)
|
|
3077
|
+
|
|
3078
|
+
with tempfile.TemporaryDirectory() as d:
|
|
3079
|
+
with mock.patch.object(
|
|
3080
|
+
metadata_listing, "_run_retrieve", side_effect=_capture,
|
|
3081
|
+
):
|
|
3082
|
+
metadata_listing.retrieve_prompt_templates(
|
|
3083
|
+
"org-alias", ["A", "B", "C"], Path(d),
|
|
3084
|
+
)
|
|
3085
|
+
|
|
3086
|
+
self.assertEqual(len(captured_argv), 1)
|
|
3087
|
+
argv = captured_argv[0]
|
|
3088
|
+
self.assertEqual(argv.count("--metadata"), 3)
|
|
3089
|
+
# Each `--metadata` flag MUST be followed by a single
|
|
3090
|
+
# `GenAiPromptTemplate:<name>` — never a comma-joined string.
|
|
3091
|
+
for name in ("A", "B", "C"):
|
|
3092
|
+
spec = f"GenAiPromptTemplate:{name}"
|
|
3093
|
+
idx = argv.index(spec)
|
|
3094
|
+
self.assertEqual(argv[idx - 1], "--metadata")
|
|
3095
|
+
self.assertNotIn(",", spec)
|
|
3096
|
+
|
|
3097
|
+
|
|
3098
|
+
class CollectPromptTemplateNamesTests(unittest.TestCase):
|
|
3099
|
+
"""Gap C: `_collect_prompt_template_names` walks topics + plannerActions
|
|
3100
|
+
and returns the set of DeveloperNames that should be passed to
|
|
3101
|
+
`retrieve_prompt_templates`. Defensive against residual 0hf-Ids
|
|
3102
|
+
(normalization missed) so the retrieve CLI doesn't get a malformed
|
|
3103
|
+
spec."""
|
|
3104
|
+
|
|
3105
|
+
def test_collects_topic_action_names(self):
|
|
3106
|
+
bundle = {
|
|
3107
|
+
"topics": [{
|
|
3108
|
+
"actions": [
|
|
3109
|
+
{"invocationTarget": "Foo_Tpl",
|
|
3110
|
+
"invocationTargetType": "GenAiPromptTemplate"},
|
|
3111
|
+
{"invocationTarget": "Bar_Tpl",
|
|
3112
|
+
"invocationTargetType": "generatePromptResponse"},
|
|
3113
|
+
],
|
|
3114
|
+
}],
|
|
3115
|
+
"plannerActions": [],
|
|
3116
|
+
}
|
|
3117
|
+
names = main._collect_prompt_template_names(bundle)
|
|
3118
|
+
self.assertEqual(names, {"Foo_Tpl", "Bar_Tpl"})
|
|
3119
|
+
|
|
3120
|
+
def test_collects_planner_action_names(self):
|
|
3121
|
+
bundle = {
|
|
3122
|
+
"topics": [],
|
|
3123
|
+
"plannerActions": [
|
|
3124
|
+
{"invocationTarget": "Planner_Tpl",
|
|
3125
|
+
"invocationTargetType": "GenAiPromptTemplate"},
|
|
3126
|
+
],
|
|
3127
|
+
}
|
|
3128
|
+
names = main._collect_prompt_template_names(bundle)
|
|
3129
|
+
self.assertEqual(names, {"Planner_Tpl"})
|
|
3130
|
+
|
|
3131
|
+
def test_skips_non_prompt_ttype(self):
|
|
3132
|
+
bundle = {
|
|
3133
|
+
"topics": [{
|
|
3134
|
+
"actions": [
|
|
3135
|
+
{"invocationTarget": "MyFlow",
|
|
3136
|
+
"invocationTargetType": "flow"},
|
|
3137
|
+
{"invocationTarget": "MyApex",
|
|
3138
|
+
"invocationTargetType": "apex"},
|
|
3139
|
+
],
|
|
3140
|
+
}],
|
|
3141
|
+
"plannerActions": [],
|
|
3142
|
+
}
|
|
3143
|
+
names = main._collect_prompt_template_names(bundle)
|
|
3144
|
+
self.assertEqual(names, set())
|
|
3145
|
+
|
|
3146
|
+
def test_skips_residual_0hf_id_targets(self):
|
|
3147
|
+
"""If normalization missed an Id (template not in org
|
|
3148
|
+
list-metadata), don't send a malformed spec to retrieve."""
|
|
3149
|
+
bundle = {
|
|
3150
|
+
"topics": [{
|
|
3151
|
+
"actions": [
|
|
3152
|
+
{"invocationTarget": "0hfUv0000021mCjIAI",
|
|
3153
|
+
"invocationTargetType": "GenAiPromptTemplate"},
|
|
3154
|
+
{"invocationTarget": "Clean_Tpl",
|
|
3155
|
+
"invocationTargetType": "GenAiPromptTemplate"},
|
|
3156
|
+
],
|
|
3157
|
+
}],
|
|
3158
|
+
"plannerActions": [],
|
|
3159
|
+
}
|
|
3160
|
+
names = main._collect_prompt_template_names(bundle)
|
|
3161
|
+
self.assertEqual(names, {"Clean_Tpl"})
|
|
3162
|
+
|
|
3163
|
+
|
|
3164
|
+
class PromptTemplateBodyAttachmentTests(unittest.TestCase):
|
|
3165
|
+
"""Gap C: `_stamp_prompt_template_bodies` attaches retrieved body
|
|
3166
|
+
fields onto matching PROMPT_TEMPLATE leaves. Unmatched leaves get
|
|
3167
|
+
`_body_available = False` so the renderer can distinguish a failed
|
|
3168
|
+
retrieve from a successfully-empty body."""
|
|
3169
|
+
|
|
3170
|
+
def test_stamps_body_onto_matching_leaf(self):
|
|
3171
|
+
tree = {
|
|
3172
|
+
"root": {
|
|
3173
|
+
"kind": "BOT_DEFINITION",
|
|
3174
|
+
"children": [{
|
|
3175
|
+
"kind": "TOPIC", "api_name": "T",
|
|
3176
|
+
"children": [{
|
|
3177
|
+
"kind": "GEN_AI_FUNCTION", "api_name": "F",
|
|
3178
|
+
"children": [{
|
|
3179
|
+
"kind": "PROMPT_TEMPLATE", "api_name": "Tpl",
|
|
3180
|
+
}],
|
|
3181
|
+
}],
|
|
3182
|
+
}],
|
|
3183
|
+
},
|
|
3184
|
+
}
|
|
3185
|
+
bodies = {
|
|
3186
|
+
"Tpl": {
|
|
3187
|
+
"developerName": "Tpl",
|
|
3188
|
+
"masterLabel": "Template One",
|
|
3189
|
+
"activeVersionIdentifier": "v1",
|
|
3190
|
+
"content": "Prompt body",
|
|
3191
|
+
"inputs": [{"name": "Q", "dataType": "String"}],
|
|
3192
|
+
},
|
|
3193
|
+
}
|
|
3194
|
+
main._stamp_prompt_template_bodies(tree["root"], bodies)
|
|
3195
|
+
leaf = tree["root"]["children"][0]["children"][0]["children"][0]
|
|
3196
|
+
self.assertEqual(leaf["master_label"], "Template One")
|
|
3197
|
+
self.assertEqual(leaf["content"], "Prompt body")
|
|
3198
|
+
self.assertEqual(leaf["inputs"], [{"name": "Q", "dataType": "String"}])
|
|
3199
|
+
self.assertTrue(leaf["_body_available"])
|
|
3200
|
+
|
|
3201
|
+
def test_unmatched_leaf_gets_body_available_false(self):
|
|
3202
|
+
tree = {
|
|
3203
|
+
"root": {
|
|
3204
|
+
"kind": "BOT_DEFINITION",
|
|
3205
|
+
"children": [{
|
|
3206
|
+
"kind": "PROMPT_TEMPLATE", "api_name": "Missing",
|
|
3207
|
+
}],
|
|
3208
|
+
},
|
|
3209
|
+
}
|
|
3210
|
+
main._stamp_prompt_template_bodies(tree["root"], {})
|
|
3211
|
+
self.assertFalse(tree["root"]["children"][0]["_body_available"])
|
|
3212
|
+
self.assertNotIn("content", tree["root"]["children"][0])
|
|
3213
|
+
|
|
3214
|
+
def test_does_not_touch_non_prompt_leaves(self):
|
|
3215
|
+
tree = {
|
|
3216
|
+
"root": {
|
|
3217
|
+
"kind": "BOT_DEFINITION",
|
|
3218
|
+
"children": [
|
|
3219
|
+
{"kind": "APEX", "api_name": "Cls"},
|
|
3220
|
+
{"kind": "FLOW", "api_name": "Flw"},
|
|
3221
|
+
],
|
|
3222
|
+
},
|
|
3223
|
+
}
|
|
3224
|
+
main._stamp_prompt_template_bodies(
|
|
3225
|
+
tree["root"], {"Cls": {"content": "x"}, "Flw": {"content": "y"}},
|
|
3226
|
+
)
|
|
3227
|
+
# Neither APEX nor FLOW leaves gain body fields.
|
|
3228
|
+
self.assertNotIn("content", tree["root"]["children"][0])
|
|
3229
|
+
self.assertNotIn("_body_available", tree["root"]["children"][0])
|
|
3230
|
+
self.assertNotIn("content", tree["root"]["children"][1])
|
|
3231
|
+
self.assertNotIn("_body_available", tree["root"]["children"][1])
|
|
3232
|
+
|
|
3233
|
+
|
|
3234
|
+
class TreeChildOrderingTests(unittest.TestCase):
|
|
3235
|
+
"""Schema 3.1 (2026-05-05) pins deterministic child ordering at the
|
|
3236
|
+
tree's single source of truth (`finalize.sort_tree_in_place`) so
|
|
3237
|
+
downstream readers see a byte-stable order regardless of Builder
|
|
3238
|
+
reorder operations or SOQL result-set sequencing.
|
|
3239
|
+
|
|
3240
|
+
Contract:
|
|
3241
|
+
- `BOT_DEFINITION.children`: TOPIC nodes first (alpha, case-insensitive);
|
|
3242
|
+
non-topic plannerActions follow as a distinct trailing group.
|
|
3243
|
+
- Each TOPIC's children: alpha by api_name, case-insensitive.
|
|
3244
|
+
- FLOW children untouched — flow-actionCall order is semantically
|
|
3245
|
+
the author's execution sequence.
|
|
3246
|
+
"""
|
|
3247
|
+
|
|
3248
|
+
def _sort(self, root: dict) -> dict:
|
|
3249
|
+
from finalize import sort_tree_in_place
|
|
3250
|
+
sort_tree_in_place(root)
|
|
3251
|
+
return root
|
|
3252
|
+
|
|
3253
|
+
def test_topics_sorted_alphabetical_case_insensitive(self):
|
|
3254
|
+
root = {
|
|
3255
|
+
"kind": "BOT_DEFINITION",
|
|
3256
|
+
"api_name": "Bot",
|
|
3257
|
+
"children": [
|
|
3258
|
+
{"kind": "TOPIC", "api_name": "Zeta", "children": []},
|
|
3259
|
+
{"kind": "TOPIC", "api_name": "alpha", "children": []},
|
|
3260
|
+
{"kind": "TOPIC", "api_name": "Mike", "children": []},
|
|
3261
|
+
],
|
|
3262
|
+
}
|
|
3263
|
+
self._sort(root)
|
|
3264
|
+
names = [c["api_name"] for c in root["children"]]
|
|
3265
|
+
self.assertEqual(names, ["alpha", "Mike", "Zeta"])
|
|
3266
|
+
|
|
3267
|
+
def test_topics_precede_planner_level_actions(self):
|
|
3268
|
+
"""Non-topic plannerAction children (e.g. a GEN_AI_FUNCTION hung
|
|
3269
|
+
directly off the planner, no parent TOPIC) MUST render after all
|
|
3270
|
+
TOPIC children, regardless of api_name ordering. The "planner-
|
|
3271
|
+
level actions are a distinct trailing group" convention is load-
|
|
3272
|
+
bearing for humans scanning the rendered tree."""
|
|
3273
|
+
root = {
|
|
3274
|
+
"kind": "BOT_DEFINITION",
|
|
3275
|
+
"api_name": "Bot",
|
|
3276
|
+
"children": [
|
|
3277
|
+
# Non-topic node with an api_name that would sort FIRST
|
|
3278
|
+
# alphabetically — the tier rule must override alpha.
|
|
3279
|
+
{"kind": "GEN_AI_FUNCTION", "api_name": "aaa_action", "children": []},
|
|
3280
|
+
{"kind": "TOPIC", "api_name": "Zeta", "children": []},
|
|
3281
|
+
{"kind": "TOPIC", "api_name": "Mike", "children": []},
|
|
3282
|
+
],
|
|
3283
|
+
}
|
|
3284
|
+
self._sort(root)
|
|
3285
|
+
kinds = [c["kind"] for c in root["children"]]
|
|
3286
|
+
self.assertEqual(kinds, ["TOPIC", "TOPIC", "GEN_AI_FUNCTION"])
|
|
3287
|
+
# Alpha within the TOPIC tier is preserved.
|
|
3288
|
+
self.assertEqual(root["children"][0]["api_name"], "Mike")
|
|
3289
|
+
self.assertEqual(root["children"][1]["api_name"], "Zeta")
|
|
3290
|
+
|
|
3291
|
+
def test_topic_children_sorted_alphabetical(self):
|
|
3292
|
+
root = {
|
|
3293
|
+
"kind": "BOT_DEFINITION",
|
|
3294
|
+
"api_name": "Bot",
|
|
3295
|
+
"children": [
|
|
3296
|
+
{
|
|
3297
|
+
"kind": "TOPIC", "api_name": "OnlyTopic",
|
|
3298
|
+
"children": [
|
|
3299
|
+
{"kind": "GEN_AI_FUNCTION", "api_name": "Zebra"},
|
|
3300
|
+
{"kind": "GEN_AI_FUNCTION", "api_name": "apple"},
|
|
3301
|
+
{"kind": "GEN_AI_FUNCTION", "api_name": "Mango"},
|
|
3302
|
+
],
|
|
3303
|
+
},
|
|
3304
|
+
],
|
|
3305
|
+
}
|
|
3306
|
+
self._sort(root)
|
|
3307
|
+
kids = root["children"][0]["children"]
|
|
3308
|
+
self.assertEqual(
|
|
3309
|
+
[c["api_name"] for c in kids],
|
|
3310
|
+
["apple", "Mango", "Zebra"],
|
|
3311
|
+
)
|
|
3312
|
+
|
|
3313
|
+
def test_flow_children_order_preserved(self):
|
|
3314
|
+
"""FLOW actionCall order is the flow author's execution sequence.
|
|
3315
|
+
sort_tree_in_place does NOT descend into FLOW children."""
|
|
3316
|
+
root = {
|
|
3317
|
+
"kind": "BOT_DEFINITION",
|
|
3318
|
+
"api_name": "Bot",
|
|
3319
|
+
"children": [
|
|
3320
|
+
{
|
|
3321
|
+
"kind": "TOPIC", "api_name": "T",
|
|
3322
|
+
"children": [
|
|
3323
|
+
{
|
|
3324
|
+
"kind": "GEN_AI_FUNCTION", "api_name": "Fn",
|
|
3325
|
+
"children": [
|
|
3326
|
+
{
|
|
3327
|
+
"kind": "FLOW", "api_name": "ParentFlow",
|
|
3328
|
+
"children": [
|
|
3329
|
+
{"kind": "APEX", "api_name": "zzz"},
|
|
3330
|
+
{"kind": "APEX", "api_name": "aaa"},
|
|
3331
|
+
],
|
|
3332
|
+
},
|
|
3333
|
+
],
|
|
3334
|
+
},
|
|
3335
|
+
],
|
|
3336
|
+
},
|
|
3337
|
+
],
|
|
3338
|
+
}
|
|
3339
|
+
self._sort(root)
|
|
3340
|
+
flow = root["children"][0]["children"][0]["children"][0]
|
|
3341
|
+
self.assertEqual(
|
|
3342
|
+
[c["api_name"] for c in flow["children"]],
|
|
3343
|
+
["zzz", "aaa"],
|
|
3344
|
+
)
|
|
3345
|
+
|
|
3346
|
+
def test_empty_children_noop(self):
|
|
3347
|
+
root = {"kind": "BOT_DEFINITION", "api_name": "Bot", "children": []}
|
|
3348
|
+
self._sort(root)
|
|
3349
|
+
self.assertEqual(root["children"], [])
|
|
3350
|
+
|
|
3351
|
+
def test_missing_root_noop(self):
|
|
3352
|
+
"""Defensive — a degenerate tree shouldn't raise."""
|
|
3353
|
+
from finalize import sort_tree_in_place
|
|
3354
|
+
sort_tree_in_place(None) # type: ignore[arg-type]
|
|
3355
|
+
sort_tree_in_place({})
|
|
3356
|
+
|
|
3357
|
+
|
|
3358
|
+
if __name__ == "__main__":
|
|
3359
|
+
unittest.main()
|