@salesforce/afv-skills 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/skills/applying-slds/SKILL.md +322 -0
- package/skills/applying-slds/checklists.md +83 -0
- package/skills/applying-slds/examples.md +283 -0
- package/skills/applying-slds/guidance/README.md +83 -0
- package/skills/applying-slds/guidance/blueprints-index.md +213 -0
- package/skills/applying-slds/guidance/icons-guidance.md +186 -0
- package/skills/applying-slds/guidance/overviews/borders.md +236 -0
- package/skills/applying-slds/guidance/overviews/color.md +266 -0
- package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
- package/skills/applying-slds/guidance/overviews/icons.md +240 -0
- package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
- package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
- package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
- package/skills/applying-slds/guidance/overviews/typography.md +323 -0
- package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
- package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
- package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
- package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
- package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
- package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
- package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
- package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
- package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
- package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
- package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
- package/skills/applying-slds/guidance/utilities/borders.md +131 -0
- package/skills/applying-slds/guidance/utilities/box.md +125 -0
- package/skills/applying-slds/guidance/utilities/color.md +165 -0
- package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
- package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
- package/skills/applying-slds/guidance/utilities/floats.md +117 -0
- package/skills/applying-slds/guidance/utilities/grid.md +264 -0
- package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
- package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
- package/skills/applying-slds/guidance/utilities/index.md +205 -0
- package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
- package/skills/applying-slds/guidance/utilities/layout.md +109 -0
- package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
- package/skills/applying-slds/guidance/utilities/margin.md +155 -0
- package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
- package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
- package/skills/applying-slds/guidance/utilities/padding.md +155 -0
- package/skills/applying-slds/guidance/utilities/position.md +177 -0
- package/skills/applying-slds/guidance/utilities/print.md +114 -0
- package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
- package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
- package/skills/applying-slds/guidance/utilities/themes.md +121 -0
- package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
- package/skills/applying-slds/guidance/utilities/typography.md +166 -0
- package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
- package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
- package/skills/applying-slds/metadata/README.md +84 -0
- package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
- package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
- package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
- package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
- package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
- package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
- package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
- package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
- package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
- package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
- package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
- package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
- package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
- package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
- package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
- package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
- package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
- package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
- package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
- package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
- package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
- package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
- package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
- package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
- package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
- package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
- package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
- package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
- package/skills/applying-slds/metadata/hooks-index.json +6272 -0
- package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
- package/skills/applying-slds/metadata/utilities-index.json +21912 -0
- package/skills/applying-slds/references/component-selection.md +112 -0
- package/skills/applying-slds/references/icons-decision-guide.md +124 -0
- package/skills/applying-slds/references/styling-decision-guide.md +228 -0
- package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
- package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
- package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
- package/skills/applying-slds/scripts/search-icons.cjs +174 -0
- package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
- package/skills/building-ui-bundle-app/SKILL.md +33 -8
- package/skills/generating-custom-application/SKILL.md +1 -1
- package/skills/generating-custom-lightning-type/SKILL.md +17 -39
- package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
- package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
- package/skills/generating-ui-bundle-custom-app/SKILL.md +93 -0
- package/skills/generating-ui-bundle-custom-app/docs/configure-metadata-custom-application.md +70 -0
- package/skills/generating-ui-bundle-metadata/SKILL.md +39 -1
- package/skills/investigating-agentforce-architecture/README.md +156 -0
- package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
- package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
- package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
- package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
- package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
- package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
- package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
- package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
- package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
- package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
- package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
- package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
- package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
- package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
- package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
- package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
- package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
- package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
- package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
- package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
- package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
- package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
- package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
- package/skills/investigating-agentforce-d360/README.md +123 -0
- package/skills/investigating-agentforce-d360/SKILL.md +163 -0
- package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
- package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
- package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
- package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
- package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
- package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
- package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
- package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
- package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
- package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
- package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
- package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
- package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
- package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
- package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
- package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
- package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
- package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
- package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
- package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
- package/skills/managing-managed-event-subscription/SKILL.md +152 -0
- package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
- package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
- package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
- package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
- package/skills/reviewing-lwc-mobile-offline/SKILL.md +168 -0
- package/skills/reviewing-lwc-mobile-offline/references/grounding.md +7 -0
- package/skills/reviewing-lwc-mobile-offline/references/inline-graphql.md +43 -0
- package/skills/reviewing-lwc-mobile-offline/references/komaci-eslint.md +125 -0
- package/skills/reviewing-lwc-mobile-offline/references/lwc-if.md +78 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/komaci.config.mjs +18 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/package.json +10 -0
- package/skills/reviewing-lwc-mobile-offline/scripts/run-komaci.sh +69 -0
- package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
- package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
- package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
- package/skills/using-mobile-native-capabilities/SKILL.md +182 -0
- package/skills/using-mobile-native-capabilities/references/app-review.md +68 -0
- package/skills/using-mobile-native-capabilities/references/ar-space-capture.md +125 -0
- package/skills/using-mobile-native-capabilities/references/barcode-scanner.md +219 -0
- package/skills/using-mobile-native-capabilities/references/base-capability.md +22 -0
- package/skills/using-mobile-native-capabilities/references/biometrics.md +90 -0
- package/skills/using-mobile-native-capabilities/references/calendar.md +213 -0
- package/skills/using-mobile-native-capabilities/references/contacts.md +232 -0
- package/skills/using-mobile-native-capabilities/references/document-scanner.md +342 -0
- package/skills/using-mobile-native-capabilities/references/geofencing.md +123 -0
- package/skills/using-mobile-native-capabilities/references/location.md +158 -0
- package/skills/using-mobile-native-capabilities/references/mobile-capabilities.md +30 -0
- package/skills/using-mobile-native-capabilities/references/nfc.md +181 -0
- package/skills/using-mobile-native-capabilities/references/payments.md +95 -0
- package/skills/validating-slds/SKILL.md +262 -0
- package/skills/validating-slds/references/quality-checks.md +308 -0
- package/skills/validating-slds/references/report-format.md +302 -0
- package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Final-phase RESULT emitter for investigating-agentforce-architecture.
|
|
3
|
+
|
|
4
|
+
Reads `$WORK_DIR/.emit_ctx.json` (populated by write_emit_ctx.py) and prints
|
|
5
|
+
the final output:
|
|
6
|
+
|
|
7
|
+
1. One-line prose status (for humans; first signal in the log).
|
|
8
|
+
2. A blank line.
|
|
9
|
+
3. The `=== RESULT ===` KV block.
|
|
10
|
+
|
|
11
|
+
BEFORE writing to stdout, the complete RESULT block is teed to
|
|
12
|
+
`$DATA_DIR/last_result_block.txt`. Writing the tee first means a consumer
|
|
13
|
+
reading the file can never see a truncated block — disk write is atomic
|
|
14
|
+
(`tmp + os.replace`), and the stdout print is a best-effort afterthought.
|
|
15
|
+
|
|
16
|
+
The callers that abort early (AGENT_NOT_FOUND, AGENT_VERSION_NOT_FOUND,
|
|
17
|
+
INVALID_INPUT) emit their own RESULT blocks directly — resolve_bot.py and
|
|
18
|
+
fs_guard.py have the same disk-tee discipline. All other terminal paths
|
|
19
|
+
(OK, PARTIAL_OK, AUTH_REQUIRED, RETRIEVE_FAILED, WRITE_FAILED) flow through
|
|
20
|
+
this script.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
python3 emit_result.py
|
|
24
|
+
|
|
25
|
+
Inputs:
|
|
26
|
+
env $WORK_DIR reads $WORK_DIR/.emit_ctx.json
|
|
27
|
+
|
|
28
|
+
Outputs:
|
|
29
|
+
$DATA_DIR/last_result_block.txt full RESULT block (atomic write)
|
|
30
|
+
stdout prose line + RESULT block
|
|
31
|
+
exit 0 always (this script emits; the bash
|
|
32
|
+
harness decides the agent's exit code)
|
|
33
|
+
exit 1 missing env, missing ctx file, bad JSON
|
|
34
|
+
"""
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import pathlib
|
|
38
|
+
import sys
|
|
39
|
+
import time
|
|
40
|
+
|
|
41
|
+
STATUS_ENUM = {
|
|
42
|
+
"OK",
|
|
43
|
+
"PARTIAL_OK",
|
|
44
|
+
"INVALID_INPUT",
|
|
45
|
+
"AUTH_REQUIRED",
|
|
46
|
+
"AGENT_NOT_FOUND",
|
|
47
|
+
"AGENT_VERSION_NOT_FOUND",
|
|
48
|
+
"RETRIEVE_FAILED",
|
|
49
|
+
"WRITE_FAILED",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
PROSE = {
|
|
53
|
+
"OK": "Declared action tree discovered and cached.",
|
|
54
|
+
"PARTIAL_OK": "Declared action tree partially discovered — see UNRESOLVED_COUNT.",
|
|
55
|
+
"INVALID_INPUT": "Input validation failed.",
|
|
56
|
+
"AUTH_REQUIRED": "sf CLI not authenticated for this org.",
|
|
57
|
+
"AGENT_NOT_FOUND": "BotDefinition.DeveloperName not found in the org.",
|
|
58
|
+
"AGENT_VERSION_NOT_FOUND": "No matching BotVersion under the bot.",
|
|
59
|
+
"RETRIEVE_FAILED": "Metadata API retrieve failed (auth/network/permissions).",
|
|
60
|
+
"WRITE_FAILED": "A filesystem write failed during finalize.",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def scrub(s) -> str:
|
|
65
|
+
if not isinstance(s, str):
|
|
66
|
+
s = "" if s is None else str(s)
|
|
67
|
+
bad = set("`$\"\\\r\t\0\n")
|
|
68
|
+
return "".join(c for c in s if c not in bad)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def bool_str(v) -> str:
|
|
72
|
+
if isinstance(v, bool):
|
|
73
|
+
return "true" if v else "false"
|
|
74
|
+
s = str(v).lower()
|
|
75
|
+
return "true" if s in ("true", "1", "yes", "on") else "false"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def build_block(ctx: dict, wall_time_seconds: float) -> str:
|
|
79
|
+
status = (ctx.get("status") or "").strip().upper()
|
|
80
|
+
if status not in STATUS_ENUM:
|
|
81
|
+
status = "WRITE_FAILED"
|
|
82
|
+
|
|
83
|
+
lines = ["=== RESULT ===", f"STATUS={status}"]
|
|
84
|
+
|
|
85
|
+
error_detail = scrub(ctx.get("error_detail", ""))
|
|
86
|
+
if error_detail:
|
|
87
|
+
lines.append(f"ERROR_DETAIL={error_detail}")
|
|
88
|
+
|
|
89
|
+
# Always-emitted identity fields (may be empty on early-abort paths)
|
|
90
|
+
lines.extend([
|
|
91
|
+
f"AGENT_API_NAME={scrub(ctx.get('agent_api_name', ''))}",
|
|
92
|
+
f"AGENT_VERSION={scrub(ctx.get('agent_version', ''))}",
|
|
93
|
+
f"VERSION_AUTO_PICKED={bool_str(ctx.get('version_auto_picked', False))}",
|
|
94
|
+
f"AGENT_GENERATION={scrub(ctx.get('agent_generation', '') or 'unknown')}",
|
|
95
|
+
f"BOT_ID={scrub(ctx.get('bot_id', ''))}",
|
|
96
|
+
f"ORG_ID_15={scrub(ctx.get('org_id_15', ''))}",
|
|
97
|
+
f"ORG_ID_18={scrub(ctx.get('org_id_18', ''))}",
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
# Output + cache paths (populated on success; may be empty on fail paths)
|
|
101
|
+
# OUTPUT_ARCHITECTURE_PATH is always emitted — empty
|
|
102
|
+
# string on fail paths, cache-hit paths where the renderer wasn't
|
|
103
|
+
# invoked, or when render failed. Downstream consumers can distinguish
|
|
104
|
+
# "no architecture produced" from "architecture produced but stale"
|
|
105
|
+
# by cross-referencing RENDER_FAILED + CACHE_HIT.
|
|
106
|
+
lines.extend([
|
|
107
|
+
f"OUTPUT_JSON_PATH={scrub(ctx.get('output_json_path', ''))}",
|
|
108
|
+
f"OUTPUT_SUMMARY_PATH={scrub(ctx.get('output_summary_path', ''))}",
|
|
109
|
+
f"OUTPUT_ARCHITECTURE_PATH={scrub(ctx.get('architecture_path', '') or '')}",
|
|
110
|
+
f"CACHE_PATH={scrub(ctx.get('cache_path', ''))}",
|
|
111
|
+
f"CACHE_HIT={bool_str(ctx.get('cache_hit', False))}",
|
|
112
|
+
f"CACHED_AT_UTC={scrub(ctx.get('cached_at_utc', ''))}",
|
|
113
|
+
])
|
|
114
|
+
|
|
115
|
+
# Tree stats
|
|
116
|
+
# emit `_partial_reason` + a rollup of `_pending_fetches` counts
|
|
117
|
+
# alongside the existing PARTIAL / UNRESOLVED_COUNT fields. The write
|
|
118
|
+
# path populates ctx["partial"], ctx["partial_reason"], and
|
|
119
|
+
# ctx["pending_fetches_count"] from the finalized tree JSON —
|
|
120
|
+
# emit_result is intentionally presentation-only and does not re-read
|
|
121
|
+
# the tree itself (ctx is the single source of truth per the emit
|
|
122
|
+
# contract).
|
|
123
|
+
partial_flag = bool(ctx.get("partial", False))
|
|
124
|
+
partial_reason = scrub(ctx.get("partial_reason", "") or "")
|
|
125
|
+
pending_fetches_count = int(ctx.get("pending_fetches_count", 0) or 0)
|
|
126
|
+
|
|
127
|
+
# If the upstream pipeline forgot to populate partial_reason but
|
|
128
|
+
# flagged partial=True, emit an empty value rather than nothing —
|
|
129
|
+
# downstream consumers can distinguish "no reason supplied" from
|
|
130
|
+
# "key missing" this way.
|
|
131
|
+
lines.extend([
|
|
132
|
+
f"NODE_COUNT={int(ctx.get('node_count', 0) or 0)}",
|
|
133
|
+
f"DEPTH={int(ctx.get('depth', 0) or 0)}",
|
|
134
|
+
f"PARTIAL={bool_str(partial_flag)}",
|
|
135
|
+
f"PARTIAL_REASON={partial_reason}",
|
|
136
|
+
f"PENDING_FETCHES_COUNT={pending_fetches_count}",
|
|
137
|
+
f"UNRESOLVED_COUNT={int(ctx.get('unresolved_count', 0) or 0)}",
|
|
138
|
+
])
|
|
139
|
+
|
|
140
|
+
# when the tree is partial but status was left blank / "OK",
|
|
141
|
+
# auto-promote the status to PARTIAL_OK so the RESULT block reflects
|
|
142
|
+
# the tree's actual state. ERROR paths (AUTH_REQUIRED etc.) keep
|
|
143
|
+
# their original status — never clobber a failure status.
|
|
144
|
+
if partial_flag and status == "OK":
|
|
145
|
+
# positional safety — `lines[1]` is by construction
|
|
146
|
+
# "STATUS=...". If a future refactor reorders the header we want
|
|
147
|
+
# a loud failure here rather than silently rewriting the wrong
|
|
148
|
+
# line. Assertion cost is negligible; the payoff is catching a
|
|
149
|
+
# whole class of refactor bugs at test time.
|
|
150
|
+
assert lines[1].startswith("STATUS="), (
|
|
151
|
+
f"emit block reordered — lines[1]={lines[1]!r}"
|
|
152
|
+
)
|
|
153
|
+
lines[1] = "STATUS=PARTIAL_OK"
|
|
154
|
+
status = "PARTIAL_OK"
|
|
155
|
+
|
|
156
|
+
# emit RENDER_FAILED unconditionally, and auto-promote to
|
|
157
|
+
# PARTIAL_OK when the tree succeeded but the architecture.md render
|
|
158
|
+
# raised. The signal surface is:
|
|
159
|
+
# * RENDER_FAILED=true|false — always emitted.
|
|
160
|
+
# * RENDER_ERROR_DETAIL=<...> — emitted ONLY on true, redacted
|
|
161
|
+
# at write_emit_ctx-time.
|
|
162
|
+
# * STATUS auto-promoted OK -> PARTIAL_OK; _partial_reason pinned
|
|
163
|
+
# to "render-failed" when the tree wasn't already partial.
|
|
164
|
+
# ERROR paths (AUTH_REQUIRED etc.) retain their original status:
|
|
165
|
+
# render never runs in those cases, and render_failed defaults to
|
|
166
|
+
# False so the auto-promote below is a no-op.
|
|
167
|
+
render_failed = bool(ctx.get("render_failed", False))
|
|
168
|
+
lines.append(f"RENDER_FAILED={bool_str(render_failed)}")
|
|
169
|
+
if render_failed:
|
|
170
|
+
detail = scrub(ctx.get("render_error_detail", "") or "")
|
|
171
|
+
lines.append(f"RENDER_ERROR_DETAIL={detail}")
|
|
172
|
+
if status == "OK":
|
|
173
|
+
# Same positional-safety discipline as the partial auto-promote.
|
|
174
|
+
assert lines[1].startswith("STATUS="), (
|
|
175
|
+
f"emit block reordered — lines[1]={lines[1]!r}"
|
|
176
|
+
)
|
|
177
|
+
lines[1] = "STATUS=PARTIAL_OK"
|
|
178
|
+
status = "PARTIAL_OK"
|
|
179
|
+
# Pin a partial_reason so triagers can tell this apart from a
|
|
180
|
+
# tree-level partial. We walk backwards to find the existing
|
|
181
|
+
# PARTIAL_REASON line (always present — emitted above) and
|
|
182
|
+
# rewrite in place. A fresh line would create two competing
|
|
183
|
+
# reason values in the block.
|
|
184
|
+
for idx in range(len(lines) - 1, -1, -1):
|
|
185
|
+
if lines[idx].startswith("PARTIAL_REASON="):
|
|
186
|
+
# Only overwrite when the tree didn't already claim
|
|
187
|
+
# a reason — the tree's reason is more informative.
|
|
188
|
+
if lines[idx] == "PARTIAL_REASON=":
|
|
189
|
+
lines[idx] = "PARTIAL_REASON=render-failed"
|
|
190
|
+
break
|
|
191
|
+
|
|
192
|
+
# Error-path-specific optional keys
|
|
193
|
+
if status == "AGENT_NOT_FOUND":
|
|
194
|
+
bots = scrub(ctx.get("available_bots", ""))
|
|
195
|
+
if bots:
|
|
196
|
+
lines.append(f"AVAILABLE_BOTS={bots}")
|
|
197
|
+
if status == "AGENT_VERSION_NOT_FOUND":
|
|
198
|
+
vers = scrub(ctx.get("available_versions", ""))
|
|
199
|
+
if vers:
|
|
200
|
+
lines.append(f"AVAILABLE_VERSIONS={vers}")
|
|
201
|
+
|
|
202
|
+
lines.append(f"WALL_TIME_SECONDS={wall_time_seconds:.2f}")
|
|
203
|
+
return "\n".join(lines) + "\n"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def main() -> int:
|
|
207
|
+
work_dir_s = os.environ.get("WORK_DIR", "")
|
|
208
|
+
if not work_dir_s:
|
|
209
|
+
sys.stderr.write("emit_result.py: $WORK_DIR not set\n")
|
|
210
|
+
return 1
|
|
211
|
+
|
|
212
|
+
ctx_path = pathlib.Path(work_dir_s) / ".emit_ctx.json"
|
|
213
|
+
try:
|
|
214
|
+
ctx = json.loads(ctx_path.read_text())
|
|
215
|
+
except FileNotFoundError:
|
|
216
|
+
sys.stderr.write(f"emit_result.py: missing {ctx_path}\n")
|
|
217
|
+
return 1
|
|
218
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
219
|
+
sys.stderr.write(f"emit_result.py: cannot read {ctx_path}: {e}\n")
|
|
220
|
+
return 1
|
|
221
|
+
|
|
222
|
+
start_epoch = float(ctx.get("start_epoch") or time.time())
|
|
223
|
+
wall = max(0.0, time.time() - start_epoch)
|
|
224
|
+
|
|
225
|
+
data_dir_s = scrub(ctx.get("data_dir", ""))
|
|
226
|
+
if not data_dir_s:
|
|
227
|
+
# Fallback default — runtime-agnostic. Mirrors runtime.resolve_data_root()
|
|
228
|
+
# in scripts/_shared/runtime.py (the pipeline's canonical helper). This
|
|
229
|
+
# tool runs standalone (no sys.path to scripts/), so we duplicate the
|
|
230
|
+
# default rather than import. If main.py ran with --data-dir, the
|
|
231
|
+
# ctx.data_dir field already carries the override value, so this
|
|
232
|
+
# branch is only reached when the pipeline aborted before writing it.
|
|
233
|
+
data_dir_s = str(
|
|
234
|
+
pathlib.Path.home()
|
|
235
|
+
/ ".vibe"
|
|
236
|
+
/ "data"
|
|
237
|
+
/ "investigating-agentforce-architecture"
|
|
238
|
+
/ "_agents"
|
|
239
|
+
)
|
|
240
|
+
data_dir = pathlib.Path(data_dir_s)
|
|
241
|
+
tee_path = data_dir / "last_result_block.txt"
|
|
242
|
+
|
|
243
|
+
body = build_block(ctx, wall)
|
|
244
|
+
body += f"RESULT_BLOCK_PATH={tee_path}\n"
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
248
|
+
tmp = tee_path.with_suffix(tee_path.suffix + ".tmp")
|
|
249
|
+
tmp.write_text(body)
|
|
250
|
+
os.replace(tmp, tee_path)
|
|
251
|
+
except OSError as e:
|
|
252
|
+
sys.stderr.write(f"emit_result.py: tee failed ({e}); continuing with stdout\n")
|
|
253
|
+
|
|
254
|
+
status = (ctx.get("status") or "").strip().upper()
|
|
255
|
+
prose = PROSE.get(status, f"Unknown status {status}.")
|
|
256
|
+
sys.stdout.write(prose + "\n\n")
|
|
257
|
+
sys.stdout.write(body)
|
|
258
|
+
return 0
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
if __name__ == "__main__":
|
|
262
|
+
sys.exit(main())
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Scrub dangerous characters from a string before splicing into the RESULT block.
|
|
3
|
+
|
|
4
|
+
Strips characters that would corrupt the `KEY=VALUE` line format parsers use to read
|
|
5
|
+
the RESULT block: backtick, dollar, double-quote, backslash, CR, tab, NUL, newline.
|
|
6
|
+
|
|
7
|
+
Used when interpolating user-controlled values (session_id, org_alias, sf CLI stderr
|
|
8
|
+
excerpts) into ERROR_DETAIL and other RESULT fields. Without scrubbing, a malicious
|
|
9
|
+
or malformed input could inject fake KEY=VALUE pairs that downstream consumers
|
|
10
|
+
would treat as authoritative.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
_safe=$(python3 "$SKILL/tools/sanitize.py" "$raw_value")
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
argv[1] raw string (may be empty)
|
|
17
|
+
|
|
18
|
+
Output:
|
|
19
|
+
stdout scrubbed string (no trailing newline)
|
|
20
|
+
exit 0 always (even on empty input)
|
|
21
|
+
"""
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
BAD = set("`$\"\\\r\t\0\n")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def scrub(s: str) -> str:
|
|
28
|
+
return "".join(c for c in s if c not in BAD)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
raw = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
33
|
+
sys.stdout.write(scrub(raw))
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Write the `$WORK_DIR/.emit_ctx.json` context file for `emit_result.py`.
|
|
3
|
+
|
|
4
|
+
The agent's bash pipeline has ~10 places where it needs to populate this
|
|
5
|
+
context file (one OK path + 6 error paths + cache-hit path). Previously this
|
|
6
|
+
was done with inline `python3 - <<PYCTX` heredocs; extracting it into one
|
|
7
|
+
script gives a stable allowlist footprint and a single source of truth for
|
|
8
|
+
the ctx-file shape.
|
|
9
|
+
|
|
10
|
+
This script reads every field from env vars the agent has already exported
|
|
11
|
+
and writes the JSON atomically. Status-specific error messages come in via
|
|
12
|
+
`STATUS` + `ERROR_DETAIL`; the rest of the fields are derived from the run's
|
|
13
|
+
already-exported state.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
STATUS=OK ERROR_DETAIL='' CACHE_HIT=false \\
|
|
17
|
+
python3 write_emit_ctx.py
|
|
18
|
+
|
|
19
|
+
Inputs (env):
|
|
20
|
+
WORK_DIR required — target dir for .emit_ctx.json
|
|
21
|
+
AGENT_API_NAME required
|
|
22
|
+
AGENT_VERSION required on success paths, may be empty on early fails
|
|
23
|
+
VERSION_AUTO_PICKED 'true'/'false'; defaults to false
|
|
24
|
+
AGENT_GENERATION 'classic'|'nga'|'unknown'; defaults to 'unknown'
|
|
25
|
+
BOT_ID required on success paths, may be empty on early fails
|
|
26
|
+
ORG_ID_15 required on success paths, may be empty on early fails
|
|
27
|
+
ORG_ID_18 required on success paths, may be empty on early fails
|
|
28
|
+
CACHE_HIT 'true'/'false'; defaults to false
|
|
29
|
+
CACHED_AT_UTC ISO-8601 or empty
|
|
30
|
+
NODE_COUNT integer as string; defaults to 0
|
|
31
|
+
DEPTH integer as string; defaults to 0
|
|
32
|
+
PARTIAL 'true'/'false'; defaults to false
|
|
33
|
+
UNRESOLVED_COUNT integer as string; defaults to 0
|
|
34
|
+
START_EPOCH float seconds since epoch
|
|
35
|
+
DATA_DIR required — absolute path (may be org-less sentinel dir on early fail)
|
|
36
|
+
CACHE_PATH optional — absolute path to cache dir (ends with /)
|
|
37
|
+
OUTPUT_JSON_PATH optional — computed if empty on OK path
|
|
38
|
+
OUTPUT_SUMMARY_PATH optional — computed if empty on OK path
|
|
39
|
+
AVAILABLE_BOTS optional — csv, for AGENT_NOT_FOUND
|
|
40
|
+
AVAILABLE_VERSIONS optional — csv, for AGENT_VERSION_NOT_FOUND
|
|
41
|
+
STATUS required — one of the 7 enum values
|
|
42
|
+
ERROR_DETAIL optional — human-readable error message
|
|
43
|
+
|
|
44
|
+
(REMEDIATE) derived keys (read from tree JSON, not env):
|
|
45
|
+
ctx["partial_reason"] from tree["_partial_reason"] (default "")
|
|
46
|
+
ctx["pending_fetches_count"] sum(len(v) for v in tree["_pending_fetches"].values())
|
|
47
|
+
(default 0)
|
|
48
|
+
|
|
49
|
+
The tree is read from `$WORK_DIR/declared_action_tree.json` — this is
|
|
50
|
+
where parse_wave.py writes. If the file is missing / unreadable / malformed,
|
|
51
|
+
both keys default to empty / 0 (pre-remediation behavior). This keeps
|
|
52
|
+
early-abort paths (AGENT_NOT_FOUND / AUTH_REQUIRED / etc.) working —
|
|
53
|
+
they never produce a tree and rightly surface `partial_reason=""` +
|
|
54
|
+
`pending_fetches_count=0`.
|
|
55
|
+
|
|
56
|
+
derived keys (read from data_dir, not env):
|
|
57
|
+
ctx["architecture_path"] absolute path to `architecture.md` when
|
|
58
|
+
the renderer produced one, else "".
|
|
59
|
+
ctx["render_failed"] True iff a `architecture.md.error`
|
|
60
|
+
sidecar exists (written by
|
|
61
|
+
main._run_finalize on renderer exception).
|
|
62
|
+
ctx["render_error_detail"] first 200 chars of sidecar, scrubbed via
|
|
63
|
+
rest_client.redact_text. Empty when
|
|
64
|
+
render_failed is False. The redact pass
|
|
65
|
+
is defensive — the sidecar shouldn't
|
|
66
|
+
carry tokens, but exception messages
|
|
67
|
+
can carry arbitrary org content.
|
|
68
|
+
|
|
69
|
+
The sidecar convention pairs with `architecture.md`: finalize writes the
|
|
70
|
+
`.error` only on exception; emit_result's RESULT-block auto-promote to
|
|
71
|
+
PARTIAL_OK relies on this boolean to flag "tree OK, diagram skipped".
|
|
72
|
+
|
|
73
|
+
Output:
|
|
74
|
+
$WORK_DIR/.emit_ctx.json
|
|
75
|
+
exit 0 on success, 1 on missing env / write failure
|
|
76
|
+
"""
|
|
77
|
+
import json
|
|
78
|
+
import os
|
|
79
|
+
import pathlib
|
|
80
|
+
import re
|
|
81
|
+
import sys
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# local, dependency-free token scrub mirroring the patterns in
|
|
85
|
+
# `scripts/rest_client.redact_text`. Keeping the redactor inline preserves
|
|
86
|
+
# the tools/ <-> scripts/ decoupling (tools/ is stdlib-only by policy) and
|
|
87
|
+
# avoids adding a sys.path hop on every write_emit_ctx invocation. The two
|
|
88
|
+
# implementations must stay in sync; the shared regex shapes are:
|
|
89
|
+
# * Authorization: Bearer <token>
|
|
90
|
+
# * access(_)?Token=<value> in query strings
|
|
91
|
+
# * "access(_)?Token":"<value>" in JSON payloads
|
|
92
|
+
# If a new redaction pattern is added to rest_client.redact_text it MUST be
|
|
93
|
+
# mirrored here — the sidecar surface is narrow (render_architecture
|
|
94
|
+
# exception messages) so the risk of drift is low, but the dual-impl is a
|
|
95
|
+
# known trade-off for decoupling.
|
|
96
|
+
_TOOLS_AUTH_HEADER_RE = re.compile(
|
|
97
|
+
r"(Authorization:\s*Bearer\s+)[^\s\"'<>]+",
|
|
98
|
+
flags=re.IGNORECASE,
|
|
99
|
+
)
|
|
100
|
+
_TOOLS_ACCESS_TOKEN_QS_RE = re.compile(
|
|
101
|
+
r"(access[_]?token=)[^&\s\"'<>]+",
|
|
102
|
+
flags=re.IGNORECASE,
|
|
103
|
+
)
|
|
104
|
+
_TOOLS_ACCESS_TOKEN_JSON_RE = re.compile(
|
|
105
|
+
r"(\"access[_]?token\"\s*:\s*\")[^\"]*",
|
|
106
|
+
flags=re.IGNORECASE,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _redact(text: str) -> str:
|
|
111
|
+
if not text:
|
|
112
|
+
return text
|
|
113
|
+
text = _TOOLS_AUTH_HEADER_RE.sub(r"\1<redacted>", text)
|
|
114
|
+
text = _TOOLS_ACCESS_TOKEN_QS_RE.sub(r"\1<redacted>", text)
|
|
115
|
+
text = _TOOLS_ACCESS_TOKEN_JSON_RE.sub(r'\1<redacted>', text)
|
|
116
|
+
return text
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _bool(v: str) -> bool:
|
|
120
|
+
return (v or "").strip().lower() == "true"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _int(v: str, default: int = 0) -> int:
|
|
124
|
+
try:
|
|
125
|
+
return int((v or "").strip() or default)
|
|
126
|
+
except ValueError:
|
|
127
|
+
return default
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _read_architecture_signals(
|
|
131
|
+
data_dir: str,
|
|
132
|
+
agent_api_name: str = "",
|
|
133
|
+
agent_version: str = "",
|
|
134
|
+
) -> tuple[str, bool, str]:
|
|
135
|
+
"""surface architecture.md presence + render-failure sidecar.
|
|
136
|
+
|
|
137
|
+
filename is now self-identifying —
|
|
138
|
+
`{agent_api_name}_{agent_version}_architecture.md` (plus `.error`
|
|
139
|
+
sidecar). Callers pass both identifiers through; when either is
|
|
140
|
+
missing we fall back to the legacy bare `architecture.md` / `.error`
|
|
141
|
+
names so early-abort paths that haven't resolved an agent yet still
|
|
142
|
+
surface any stray files they produced.
|
|
143
|
+
|
|
144
|
+
Returns `(architecture_path, render_failed, render_error_detail)`:
|
|
145
|
+
|
|
146
|
+
* `architecture_path` — absolute str to the rendered architecture.md
|
|
147
|
+
when present; `""` otherwise. Empty also covers cache-hit paths
|
|
148
|
+
where a *past* run's file may exist — see the inline note.
|
|
149
|
+
* `render_failed` — True iff the `.error` sidecar exists (written by
|
|
150
|
+
main._run_finalize on renderer exception).
|
|
151
|
+
* `render_error_detail` — first 200 chars of the sidecar, stripped +
|
|
152
|
+
scrubbed via `_redact`. Empty when `render_failed` is False.
|
|
153
|
+
|
|
154
|
+
Tolerant of: missing dir, unreadable sidecar, binary content. A failure
|
|
155
|
+
to read the sidecar degrades to an empty detail string rather than
|
|
156
|
+
suppressing the render_failed flag — consumers still see the outage
|
|
157
|
+
signal, just without the triage text.
|
|
158
|
+
|
|
159
|
+
Cache-hit caveat: on a cache replay, the prior run's architecture.md
|
|
160
|
+
may still be present. We intentionally surface its path anyway (the
|
|
161
|
+
file *is* a product of this run's data_dir). Sidecar semantics are
|
|
162
|
+
different — the sidecar only lands via finalize, so a cache replay
|
|
163
|
+
cannot plant a stale `.error`.
|
|
164
|
+
"""
|
|
165
|
+
if not data_dir:
|
|
166
|
+
return ("", False, "")
|
|
167
|
+
dd = pathlib.Path(data_dir)
|
|
168
|
+
if agent_api_name and agent_version:
|
|
169
|
+
arch = dd / f"{agent_api_name}_{agent_version}_architecture.md"
|
|
170
|
+
sidecar = dd / f"{agent_api_name}_{agent_version}_architecture.md.error"
|
|
171
|
+
else:
|
|
172
|
+
# Early-abort paths (no agent resolved) fall back to the legacy
|
|
173
|
+
# bare name so any stray file still surfaces.
|
|
174
|
+
arch = dd / "architecture.md"
|
|
175
|
+
sidecar = dd / "architecture.md.error"
|
|
176
|
+
|
|
177
|
+
arch_path = str(arch) if arch.is_file() else ""
|
|
178
|
+
|
|
179
|
+
if not sidecar.is_file():
|
|
180
|
+
return (arch_path, False, "")
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
# read_text()'s default is utf-8 with strict errors; a sidecar
|
|
184
|
+
# written by finalize is always ascii prose, but be defensive in
|
|
185
|
+
# case future code changes widen the content set.
|
|
186
|
+
raw = sidecar.read_text(errors="replace")
|
|
187
|
+
except OSError:
|
|
188
|
+
return (arch_path, True, "")
|
|
189
|
+
|
|
190
|
+
# Truncate to a single-line-ish detail string. The sidecar format is
|
|
191
|
+
# `"render_architecture failed: <ExcType>: <msg>\n"`; we strip + cap
|
|
192
|
+
# at 200 chars to keep the RESULT block readable, then scrub.
|
|
193
|
+
detail = raw.strip().splitlines()[0] if raw.strip() else ""
|
|
194
|
+
detail = _redact(detail)[:200]
|
|
195
|
+
return (arch_path, True, detail)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _read_tree_partial_signals(work_dir: str) -> tuple[str, int]:
|
|
199
|
+
"""extract `_partial_reason` + pending-fetches rollup from the tree.
|
|
200
|
+
|
|
201
|
+
Reads `$WORK_DIR/declared_action_tree.json` (parse_wave's output) and
|
|
202
|
+
returns `(partial_reason, pending_fetches_count)`.
|
|
203
|
+
|
|
204
|
+
Tolerant of: missing file, unreadable file, malformed JSON, missing
|
|
205
|
+
keys, wrong-typed keys. All of those degrade to `("", 0)` — the
|
|
206
|
+
pre-remediation defaults — so early-abort code paths (which never
|
|
207
|
+
produce a tree) behave unchanged.
|
|
208
|
+
|
|
209
|
+
This is intentionally defensive: write_emit_ctx runs on every exit
|
|
210
|
+
path, including ones where the tree was never created. A raise here
|
|
211
|
+
would turn a clean error status into a write failure.
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
tree_path = pathlib.Path(work_dir) / "declared_action_tree.json"
|
|
215
|
+
if not tree_path.is_file():
|
|
216
|
+
return ("", 0)
|
|
217
|
+
tree = json.loads(tree_path.read_text())
|
|
218
|
+
except (OSError, json.JSONDecodeError):
|
|
219
|
+
return ("", 0)
|
|
220
|
+
|
|
221
|
+
if not isinstance(tree, dict):
|
|
222
|
+
return ("", 0)
|
|
223
|
+
|
|
224
|
+
reason_raw = tree.get("_partial_reason")
|
|
225
|
+
reason = reason_raw if isinstance(reason_raw, str) else ""
|
|
226
|
+
|
|
227
|
+
pending = tree.get("_pending_fetches")
|
|
228
|
+
count = 0
|
|
229
|
+
if isinstance(pending, dict):
|
|
230
|
+
for v in pending.values():
|
|
231
|
+
if isinstance(v, list):
|
|
232
|
+
count += len(v)
|
|
233
|
+
|
|
234
|
+
return (reason, count)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def main() -> int:
|
|
238
|
+
try:
|
|
239
|
+
work_dir = os.environ["WORK_DIR"]
|
|
240
|
+
data_dir = os.environ["DATA_DIR"]
|
|
241
|
+
status = os.environ["STATUS"]
|
|
242
|
+
except KeyError as e:
|
|
243
|
+
sys.stderr.write(f"write_emit_ctx.py: missing env {e}\n")
|
|
244
|
+
return 1
|
|
245
|
+
|
|
246
|
+
agent_api_name = os.environ.get("AGENT_API_NAME", "")
|
|
247
|
+
agent_version = os.environ.get("AGENT_VERSION", "")
|
|
248
|
+
org_id_15 = os.environ.get("ORG_ID_15", "")
|
|
249
|
+
|
|
250
|
+
# Default OUTPUT_*_PATH paths follow the agent-scoped naming convention.
|
|
251
|
+
# Caller can override by exporting directly. If DATA_DIR already ends with
|
|
252
|
+
# the per-agent suffix (because the agent bash composed it), don't re-append.
|
|
253
|
+
#
|
|
254
|
+
# summary.md dropped from the output contract — OUTPUT_SUMMARY_PATH
|
|
255
|
+
# is kept in the RESULT block (empty string) for shape stability.
|
|
256
|
+
default_json = ""
|
|
257
|
+
if status in ("OK", "PARTIAL_OK") and org_id_15 and agent_api_name and agent_version:
|
|
258
|
+
per_agent_suffix = f"{org_id_15}/{agent_api_name}__{agent_version}"
|
|
259
|
+
dd = data_dir.rstrip("/")
|
|
260
|
+
base = dd if dd.endswith(per_agent_suffix) else f"{dd}/{per_agent_suffix}"
|
|
261
|
+
default_json = f"{base}/{agent_api_name}_{agent_version}_metadata_tree.json"
|
|
262
|
+
|
|
263
|
+
output_json = os.environ.get("OUTPUT_JSON_PATH") or default_json
|
|
264
|
+
output_summary = os.environ.get("OUTPUT_SUMMARY_PATH") or ""
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
start_epoch = float(os.environ.get("START_EPOCH", "0") or "0")
|
|
268
|
+
except ValueError:
|
|
269
|
+
start_epoch = 0.0
|
|
270
|
+
|
|
271
|
+
# derive partial_reason + pending_fetches_count from the tree
|
|
272
|
+
# on disk rather than relying on the agent bash to export them. The
|
|
273
|
+
# tree is the single source of truth — parse_wave wrote these fields;
|
|
274
|
+
# having the bash re-export them would be a narrow, drift-prone
|
|
275
|
+
# integration layer. Absent tree → default ("", 0).
|
|
276
|
+
partial_reason, pending_fetches_count = _read_tree_partial_signals(work_dir)
|
|
277
|
+
|
|
278
|
+
# derive architecture-output signals from the data_dir.
|
|
279
|
+
# Parallel to the partial-signals plumbing above: data_dir is the
|
|
280
|
+
# single source of truth for what finalize produced. A missing dir
|
|
281
|
+
# (early-abort paths) degrades to empty fields and render_failed=False.
|
|
282
|
+
architecture_path, render_failed, render_error_detail = (
|
|
283
|
+
_read_architecture_signals(data_dir, agent_api_name, agent_version)
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
ctx = {
|
|
287
|
+
"status": status,
|
|
288
|
+
"error_detail": os.environ.get("ERROR_DETAIL", ""),
|
|
289
|
+
"agent_api_name": agent_api_name,
|
|
290
|
+
"agent_version": agent_version,
|
|
291
|
+
"version_auto_picked": _bool(os.environ.get("VERSION_AUTO_PICKED", "")),
|
|
292
|
+
"agent_generation": os.environ.get("AGENT_GENERATION", "") or "unknown",
|
|
293
|
+
"bot_id": os.environ.get("BOT_ID", ""),
|
|
294
|
+
"org_id_15": org_id_15,
|
|
295
|
+
"org_id_18": os.environ.get("ORG_ID_18", ""),
|
|
296
|
+
"cache_hit": _bool(os.environ.get("CACHE_HIT", "")),
|
|
297
|
+
"cached_at_utc": os.environ.get("CACHED_AT_UTC", ""),
|
|
298
|
+
"cache_path": os.environ.get("CACHE_PATH", ""),
|
|
299
|
+
"output_json_path": output_json,
|
|
300
|
+
"output_summary_path": output_summary,
|
|
301
|
+
"node_count": _int(os.environ.get("NODE_COUNT", "0")),
|
|
302
|
+
"depth": _int(os.environ.get("DEPTH", "0")),
|
|
303
|
+
"partial": _bool(os.environ.get("PARTIAL", "")),
|
|
304
|
+
# plumbed from the tree, not env.
|
|
305
|
+
"partial_reason": partial_reason,
|
|
306
|
+
"pending_fetches_count": pending_fetches_count,
|
|
307
|
+
"unresolved_count": _int(os.environ.get("UNRESOLVED_COUNT", "0")),
|
|
308
|
+
"available_bots": os.environ.get("AVAILABLE_BOTS", ""),
|
|
309
|
+
"available_versions": os.environ.get("AVAILABLE_VERSIONS", ""),
|
|
310
|
+
"start_epoch": start_epoch,
|
|
311
|
+
"data_dir": data_dir,
|
|
312
|
+
"work_dir": work_dir,
|
|
313
|
+
# architecture-render outcome signals.
|
|
314
|
+
"architecture_path": architecture_path,
|
|
315
|
+
"render_failed": render_failed,
|
|
316
|
+
"render_error_detail": render_error_detail,
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
out = pathlib.Path(work_dir) / ".emit_ctx.json"
|
|
320
|
+
try:
|
|
321
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
322
|
+
tmp = out.with_suffix(out.suffix + ".tmp")
|
|
323
|
+
tmp.write_text(json.dumps(ctx, indent=2))
|
|
324
|
+
os.replace(tmp, out)
|
|
325
|
+
except OSError as e:
|
|
326
|
+
sys.stderr.write(f"write_emit_ctx.py: write failed: {e}\n")
|
|
327
|
+
return 1
|
|
328
|
+
return 0
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
if __name__ == "__main__":
|
|
332
|
+
sys.exit(main())
|