@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.
Files changed (359) hide show
  1. package/package.json +3 -3
  2. package/skills/applying-slds/SKILL.md +322 -0
  3. package/skills/applying-slds/checklists.md +83 -0
  4. package/skills/applying-slds/examples.md +283 -0
  5. package/skills/applying-slds/guidance/README.md +83 -0
  6. package/skills/applying-slds/guidance/blueprints-index.md +213 -0
  7. package/skills/applying-slds/guidance/icons-guidance.md +186 -0
  8. package/skills/applying-slds/guidance/overviews/borders.md +236 -0
  9. package/skills/applying-slds/guidance/overviews/color.md +266 -0
  10. package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
  11. package/skills/applying-slds/guidance/overviews/icons.md +240 -0
  12. package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
  13. package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
  14. package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
  15. package/skills/applying-slds/guidance/overviews/typography.md +323 -0
  16. package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
  17. package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
  18. package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
  19. package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
  20. package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
  21. package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
  22. package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
  23. package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
  24. package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
  25. package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
  26. package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
  27. package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
  28. package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
  29. package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
  30. package/skills/applying-slds/guidance/utilities/borders.md +131 -0
  31. package/skills/applying-slds/guidance/utilities/box.md +125 -0
  32. package/skills/applying-slds/guidance/utilities/color.md +165 -0
  33. package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
  34. package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
  35. package/skills/applying-slds/guidance/utilities/floats.md +117 -0
  36. package/skills/applying-slds/guidance/utilities/grid.md +264 -0
  37. package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
  38. package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
  39. package/skills/applying-slds/guidance/utilities/index.md +205 -0
  40. package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
  41. package/skills/applying-slds/guidance/utilities/layout.md +109 -0
  42. package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
  43. package/skills/applying-slds/guidance/utilities/margin.md +155 -0
  44. package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
  45. package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
  46. package/skills/applying-slds/guidance/utilities/padding.md +155 -0
  47. package/skills/applying-slds/guidance/utilities/position.md +177 -0
  48. package/skills/applying-slds/guidance/utilities/print.md +114 -0
  49. package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
  50. package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
  51. package/skills/applying-slds/guidance/utilities/themes.md +121 -0
  52. package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
  53. package/skills/applying-slds/guidance/utilities/typography.md +166 -0
  54. package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
  55. package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
  56. package/skills/applying-slds/metadata/README.md +84 -0
  57. package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
  58. package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
  59. package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
  60. package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
  61. package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
  62. package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
  63. package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
  64. package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
  65. package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
  66. package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
  67. package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
  68. package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
  69. package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
  70. package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
  71. package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
  72. package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
  73. package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
  74. package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
  75. package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
  76. package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
  77. package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
  78. package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
  79. package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
  80. package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
  81. package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
  82. package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
  83. package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
  84. package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
  85. package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
  86. package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
  87. package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
  88. package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
  89. package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
  90. package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
  91. package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
  92. package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
  93. package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
  94. package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
  95. package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
  96. package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
  97. package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
  98. package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
  99. package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
  100. package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
  101. package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
  102. package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
  103. package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
  104. package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
  105. package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
  106. package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
  107. package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
  108. package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
  109. package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
  110. package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
  111. package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
  112. package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
  113. package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
  114. package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
  115. package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
  116. package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
  117. package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
  118. package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
  119. package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
  120. package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
  121. package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
  122. package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
  123. package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
  124. package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
  125. package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
  126. package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
  127. package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
  128. package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
  129. package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
  130. package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
  131. package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
  132. package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
  133. package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
  134. package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
  135. package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
  136. package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
  137. package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
  138. package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
  139. package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
  140. package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
  141. package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
  142. package/skills/applying-slds/metadata/hooks-index.json +6272 -0
  143. package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
  144. package/skills/applying-slds/metadata/utilities-index.json +21912 -0
  145. package/skills/applying-slds/references/component-selection.md +112 -0
  146. package/skills/applying-slds/references/icons-decision-guide.md +124 -0
  147. package/skills/applying-slds/references/styling-decision-guide.md +228 -0
  148. package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
  149. package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
  150. package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
  151. package/skills/applying-slds/scripts/search-icons.cjs +174 -0
  152. package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
  153. package/skills/building-ui-bundle-app/SKILL.md +33 -8
  154. package/skills/generating-custom-application/SKILL.md +1 -1
  155. package/skills/generating-custom-lightning-type/SKILL.md +17 -39
  156. package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
  157. package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
  158. package/skills/generating-ui-bundle-custom-app/SKILL.md +93 -0
  159. package/skills/generating-ui-bundle-custom-app/docs/configure-metadata-custom-application.md +70 -0
  160. package/skills/generating-ui-bundle-metadata/SKILL.md +39 -1
  161. package/skills/investigating-agentforce-architecture/README.md +156 -0
  162. package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
  163. package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
  164. package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
  165. package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
  166. package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
  167. package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
  168. package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
  169. package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
  170. package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
  171. package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
  172. package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
  173. package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
  174. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
  175. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
  176. package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
  177. package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
  178. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
  179. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
  180. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
  181. package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
  182. package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
  183. package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
  184. package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
  185. package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
  186. package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
  187. package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
  188. package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
  189. package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
  190. package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
  191. package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
  192. package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
  193. package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
  194. package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
  195. package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
  196. package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
  197. package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
  198. package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
  199. package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
  200. package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
  201. package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
  202. package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
  203. package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
  204. package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
  205. package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
  206. package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
  207. package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
  208. package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
  209. package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
  210. package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
  211. package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
  212. package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
  213. package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
  214. package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
  215. package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
  216. package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
  217. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
  218. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
  219. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
  220. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
  221. package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
  222. package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
  223. package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
  224. package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
  225. package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
  226. package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
  227. package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
  228. package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
  229. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
  230. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
  231. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
  232. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
  233. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
  234. package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
  235. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
  236. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
  237. package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
  238. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
  239. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
  240. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
  241. package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
  242. package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
  243. package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
  244. package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
  245. package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
  246. package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
  247. package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
  248. package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
  249. package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
  250. package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
  251. package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
  252. package/skills/investigating-agentforce-d360/README.md +123 -0
  253. package/skills/investigating-agentforce-d360/SKILL.md +163 -0
  254. package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
  255. package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
  256. package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
  257. package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
  258. package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
  259. package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
  260. package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
  261. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
  262. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
  263. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
  264. package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
  265. package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
  266. package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
  267. package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
  268. package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
  269. package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
  270. package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
  271. package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
  272. package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
  273. package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
  274. package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
  275. package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
  276. package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
  277. package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
  278. package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
  279. package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
  280. package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
  281. package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
  282. package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
  283. package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
  284. package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
  285. package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
  286. package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
  287. package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
  288. package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
  289. package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
  290. package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
  291. package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
  292. package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
  293. package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
  294. package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
  295. package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
  296. package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
  297. package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
  298. package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
  299. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
  300. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
  301. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
  302. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
  303. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
  304. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
  305. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
  306. package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
  307. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
  308. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
  309. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
  310. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
  311. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
  312. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
  313. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
  314. package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
  315. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
  316. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
  317. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
  318. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
  319. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
  320. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
  321. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
  322. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
  323. package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
  324. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
  325. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
  326. package/skills/managing-managed-event-subscription/SKILL.md +152 -0
  327. package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
  328. package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
  329. package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
  330. package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
  331. package/skills/reviewing-lwc-mobile-offline/SKILL.md +168 -0
  332. package/skills/reviewing-lwc-mobile-offline/references/grounding.md +7 -0
  333. package/skills/reviewing-lwc-mobile-offline/references/inline-graphql.md +43 -0
  334. package/skills/reviewing-lwc-mobile-offline/references/komaci-eslint.md +125 -0
  335. package/skills/reviewing-lwc-mobile-offline/references/lwc-if.md +78 -0
  336. package/skills/reviewing-lwc-mobile-offline/scripts/komaci.config.mjs +18 -0
  337. package/skills/reviewing-lwc-mobile-offline/scripts/package.json +10 -0
  338. package/skills/reviewing-lwc-mobile-offline/scripts/run-komaci.sh +69 -0
  339. package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
  340. package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
  341. package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
  342. package/skills/using-mobile-native-capabilities/SKILL.md +182 -0
  343. package/skills/using-mobile-native-capabilities/references/app-review.md +68 -0
  344. package/skills/using-mobile-native-capabilities/references/ar-space-capture.md +125 -0
  345. package/skills/using-mobile-native-capabilities/references/barcode-scanner.md +219 -0
  346. package/skills/using-mobile-native-capabilities/references/base-capability.md +22 -0
  347. package/skills/using-mobile-native-capabilities/references/biometrics.md +90 -0
  348. package/skills/using-mobile-native-capabilities/references/calendar.md +213 -0
  349. package/skills/using-mobile-native-capabilities/references/contacts.md +232 -0
  350. package/skills/using-mobile-native-capabilities/references/document-scanner.md +342 -0
  351. package/skills/using-mobile-native-capabilities/references/geofencing.md +123 -0
  352. package/skills/using-mobile-native-capabilities/references/location.md +158 -0
  353. package/skills/using-mobile-native-capabilities/references/mobile-capabilities.md +30 -0
  354. package/skills/using-mobile-native-capabilities/references/nfc.md +181 -0
  355. package/skills/using-mobile-native-capabilities/references/payments.md +95 -0
  356. package/skills/validating-slds/SKILL.md +262 -0
  357. package/skills/validating-slds/references/quality-checks.md +308 -0
  358. package/skills/validating-slds/references/report-format.md +302 -0
  359. 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())