@salesforce/afv-skills 1.67.0 → 1.68.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 (118) hide show
  1. package/README.md +55 -5
  2. package/package.json +1 -1
  3. package/skills/agentforce-offline-experimentation-run/SKILL.md +14 -22
  4. package/skills/agentforce-offline-experimentation-run/scripts/bt_compare.py +81 -0
  5. package/skills/agentforce-offline-experimentation-run/scripts/bt_fetch.py +358 -0
  6. package/skills/agentforce-offline-experimentation-run/scripts/bt_patch_agent.py +110 -0
  7. package/skills/agentforce-offline-experimentation-run/scripts/btlib/__init__.py +34 -0
  8. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentpatch.py +483 -0
  9. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentsrc.py +565 -0
  10. package/skills/agentforce-offline-experimentation-run/scripts/btlib/cache.py +95 -0
  11. package/skills/agentforce-offline-experimentation-run/scripts/btlib/compare.py +617 -0
  12. package/skills/agentforce-offline-experimentation-run/scripts/btlib/fetch.py +1012 -0
  13. package/skills/agentforce-offline-experimentation-run/scripts/btlib/judge.py +148 -0
  14. package/skills/agentforce-offline-experimentation-run/scripts/btlib/messages.py +92 -0
  15. package/skills/agentforce-offline-experimentation-run/scripts/btlib/patch.py +327 -0
  16. package/skills/agentforce-offline-experimentation-run/scripts/btlib/redact.py +40 -0
  17. package/skills/agentforce-offline-experimentation-run/scripts/btlib/results.py +288 -0
  18. package/skills/agentforce-offline-experimentation-run/scripts/btlib/scoring.py +340 -0
  19. package/skills/agentforce-offline-experimentation-run/scripts/btlib/sfap.py +238 -0
  20. package/skills/agentforce-offline-experimentation-run/scripts/btlib/splits.py +136 -0
  21. package/skills/agentforce-offline-experimentation-run/scripts/btlib/stdm.py +98 -0
  22. package/skills/agentforce-offline-experimentation-run/scripts/btlib/tokens.py +173 -0
  23. package/skills/agentforce-offline-experimentation-run/scripts/btlib/units.py +199 -0
  24. package/skills/agentforce-offline-experimentation-run/scripts/btlib/versions.py +194 -0
  25. package/skills/agentforce-offline-experimentation-run/scripts/build_report.py +366 -378
  26. package/skills/agentforce-offline-experimentation-run/scripts/resolve-token.sh +14 -4
  27. package/skills/agentforce-offline-experimentation-run/scripts/sfap_replay.py +472 -796
  28. package/skills/dx-lifecycle-center/SKILL.md +5 -2
  29. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/connect-connected.json +65 -0
  30. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/schema.json +32 -0
  31. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/connect-sign-in.json +57 -0
  32. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/schema.json +21 -0
  33. package/skills/dx-lifecycle-center/examples/workflows.md +20 -6
  34. package/skills/dx-lifecycle-center/references/connect-org.md +21 -2
  35. package/skills/dx-lifecycle-center/references/deploy.md +2 -2
  36. package/skills/dx-lifecycle-center/references/list-orgs.md +1 -1
  37. package/skills/dx-lifecycle-center/scripts/card-policy.jq +71 -0
  38. package/skills/dx-lifecycle-center/scripts/fill-widget.jq +29 -0
  39. package/skills/dx-lifecycle-center/scripts/widget.sh +28 -0
  40. package/skills/dx-org-devhub-configure/SKILL.md +85 -84
  41. package/skills/dx-org-devhub-configure/examples/status-output.md +25 -2
  42. package/skills/dx-org-devhub-configure/scripts/devhub.sh +265 -140
  43. package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +100 -15
  44. package/skills/dx-packaging-move-to-2gp-migrate/SKILL.md +89 -0
  45. package/skills/dx-packaging-move-to-2gp-migrate/references/api-operations.md +164 -0
  46. package/skills/dx-scratch-def-configure/SKILL.md +163 -0
  47. package/skills/dx-scratch-def-configure/examples/confirm-card.md +53 -0
  48. package/skills/dx-scratch-def-configure/examples/report-recipes.md +100 -0
  49. package/skills/dx-scratch-def-configure/references/features.json +3270 -0
  50. package/skills/dx-scratch-def-configure/references/project-scratch-def.schema.json +1841 -0
  51. package/skills/dx-scratch-def-configure/references/settings-map.json +682 -0
  52. package/skills/dx-scratch-def-configure/scripts/lib_scratch_def.py +1306 -0
  53. package/skills/dx-scratch-def-configure/scripts/requirements.txt +3 -0
  54. package/skills/dx-scratch-def-configure/scripts/scrape_config_values.py +848 -0
  55. package/skills/education-cloud-domain-configure/SKILL.md +1 -1
  56. package/skills/education-cloud-multi-campus-configure/SKILL.md +1 -1
  57. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +1 -1
  58. package/skills/experience-design-validate/SKILL.md +1 -1
  59. package/skills/experience-search-coordinate/SKILL.md +18 -12
  60. package/skills/experience-search-coordinate/references/content-route.md +79 -1
  61. package/skills/field-service-data-capture-migrate/SKILL.md +1 -1
  62. package/skills/platform-apex-generate/SKILL.md +14 -11
  63. package/skills/platform-apex-test-generate/SKILL.md +2 -1
  64. package/skills/platform-datamask-run/SKILL.md +52 -71
  65. package/skills/platform-datamask-run/references/api-surface.md +10 -4
  66. package/skills/platform-datamask-run/references/policy-authoring.md +56 -7
  67. package/skills/platform-datamask-run/references/run-and-abort.md +17 -10
  68. package/skills/platform-datamask-run/scripts/poll-job.sh +15 -25
  69. package/skills/platform-dataspace-access-configure/SKILL.md +19 -1
  70. package/skills/platform-metadata-discovery-get/SKILL.md +185 -0
  71. package/skills/platform-metadata-discovery-get/references/api-map.md +25 -0
  72. package/skills/platform-metadata-discovery-get/references/h360-routes.md +30 -0
  73. package/skills/platform-metadata-discovery-get/references/scoped-soql.md +52 -0
  74. package/skills/platform-metadata-grounding-get/SKILL.md +170 -0
  75. package/skills/platform-policy-rule-generate/SKILL.md +84 -232
  76. package/skills/platform-policy-rule-generate/references/condition-model.md +47 -0
  77. package/skills/platform-policy-rule-generate/references/condition-templates.md +89 -0
  78. package/skills/platform-policy-rule-generate/references/conjunction-compiler.md +25 -0
  79. package/skills/platform-policy-rule-generate/references/conjunction-expression.md +22 -0
  80. package/skills/platform-policy-rule-generate/references/consumer-all.md +9 -0
  81. package/skills/platform-policy-rule-generate/references/consumer-datacloud-ui.md +91 -0
  82. package/skills/platform-policy-rule-generate/references/deploy-errors.md +24 -36
  83. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/package.xml +12 -0
  84. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitionSets/ExistsJoinRLS.policyRuleDefinitionSet +6 -0
  85. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitions/ExistsJoinRLS_Rule_1.policyRuleDefinition +91 -0
  86. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/package.xml +12 -0
  87. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitionSets/FieldReadDeny.policyRuleDefinitionSet +6 -0
  88. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitions/FieldReadDeny_Rule_1.policyRuleDefinition +72 -0
  89. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/package.xml +12 -0
  90. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitionSets/LastCharactersFieldMasking.policyRuleDefinitionSet +6 -0
  91. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitions/LastCharactersFieldMasking_Rule_1.policyRuleDefinition +77 -0
  92. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/package.xml +12 -0
  93. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitionSets/PrincipalFieldMatchRLS.policyRuleDefinitionSet +6 -0
  94. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitions/PrincipalFieldMatchRLS_Rule_1.policyRuleDefinition +77 -0
  95. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/package.xml +12 -0
  96. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitionSets/TaggedObjectAccess.policyRuleDefinitionSet +4 -0
  97. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitions/TaggedObjectAccess_Rule_1.policyRuleDefinition +65 -0
  98. package/skills/platform-policy-rule-generate/references/headless-transport.md +87 -0
  99. package/skills/platform-policy-rule-generate/references/policy-schema-full.md +17 -10
  100. package/skills/platform-policy-rule-generate/references/policy-shapes.md +74 -0
  101. package/skills/platform-policy-rule-generate/references/principal-expression.md +31 -0
  102. package/skills/platform-policy-rule-generate/references/reference-resolution.md +51 -0
  103. package/skills/platform-policy-rule-generate/references/resource-expression.md +48 -0
  104. package/skills/platform-policy-rule-generate/references/runtime-context.md +9 -0
  105. package/skills/platform-policy-rule-generate/references/templates-access.md +11 -9
  106. package/skills/platform-policy-rule-generate/references/templates-advanced.md +4 -2
  107. package/skills/platform-policy-rule-generate/references/templates-record.md +37 -22
  108. package/skills/platform-policy-rule-generate/references/templates-transform.md +10 -8
  109. package/skills/platform-policy-rule-generate/references/templates.md +2 -2
  110. package/skills/platform-policy-rule-generate/references/ui-compatibility.md +35 -17
  111. package/skills/platform-report-generate/SKILL.md +9 -4
  112. package/skills/platform-report-generate/references/chart-types.md +26 -2
  113. package/skills/platform-report-generate/references/column-names.md +43 -0
  114. package/skills/platform-report-generate/references/errors-and-troubleshooting.md +1 -1
  115. package/skills/platform-report-generate/references/verification-checklist.md +10 -2
  116. package/skills/service-digital-engagement-channel-configure/SKILL.md +7 -5
  117. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +33 -0
  118. package/skills/service-digital-engagement-channel-configure/references/channel_settings.md +110 -14
@@ -38,7 +38,7 @@ Connect (B) and deploy or quick deploy (D) change an org, so they wait for the u
38
38
 
39
39
  ## Routing (deterministic)
40
40
 
41
- Scripts and references are paths inside this skill's folder (the folder that holds this file). This skill owns every request below. Pick the operation by these rules **in order; the first match wins**. Do not hand these requests to another skill, and do not answer them from general knowledge.
41
+ Scripts, references, and assets are paths inside this skill's folder, `<skill_dir>`: the location given for this skill when it was listed or loaded, without the trailing `/SKILL.md`. Run every script as `bash <skill_dir>/scripts/<script>` from the current folder. Do not `cd` first (the current folder sets the default org for `sf`), and never guess another folder or search the filesystem for the skill. This skill owns every request below. Pick the operation by these rules **in order; the first match wins**. Do not hand these requests to another skill, and do not answer them from general knowledge.
42
42
 
43
43
  | # | The request | Operation |
44
44
  |---|---|---|
@@ -83,6 +83,7 @@ A bare "deploy" with no DX Inspector context is a question, not a deploy.
83
83
  - Make one attempt per API call. Never retry in a loop, resubmit after a timeout, or invent an id, credential name, or status.
84
84
  - Never ask for, print, or pass an access token. Never show row ids or credential names.
85
85
  - Never say a browser was opened. Give the login link and wait for the user to reply **done**.
86
+ - Pass `render_widget` only a `CARD_JSON` line that `scripts/widget.sh` printed, exactly as printed. Never write, invent, or edit a card.
86
87
  - Do not guess a missing input. Ask one question for the first missing input.
87
88
  - Ask the user to confirm an org type that the URL host does not decide. Never infer it from an environment name.
88
89
 
@@ -93,7 +94,7 @@ A bare "deploy" with no DX Inspector context is a question, not a deploy.
93
94
  | **A** list | Only the table and the closing sentence (`list-orgs.md`, section 4). No raw JSON, no extra offers. |
94
95
  | **A** not enabled | The one-sentence message in `list-orgs.md`, section 2. Nothing else. |
95
96
  | **B** connect | The sign-in layout with a button-style link (`connect-org.md`, Step 2), then after **done** the connected layout: environment name, org host, type, and status (`connect-org.md`, Step 5). |
96
- | **C** | The exact sentences in `hub-org.md`. When connecting, the same sign-in and connected layouts as B, in hub form. |
97
+ | **C** | The exact sentences in `hub-org.md`. When connecting, the same sign-in and connected layouts as B, in hub form, or the sign-in and connected cards when the `render_widget` tool is available (`connect-org.md`, Steps 2 and 5). |
97
98
  | **D** | A plain-language report: what was deployed, from where, to where, and the outcome (`deploy.md`, Step 7). No raw JSON. If the deploy is still running after about 2 minutes: the `requestId`, a note that it is in progress, and a request to send the id back to get the status (`deploy.md`, Step 6). |
98
99
 
99
100
  ## If something fails
@@ -118,3 +119,5 @@ A bare "deploy" with no DX Inspector context is a question, not a deploy.
118
119
  - `examples/workflows.md`: worked prompts for each operation.
119
120
  - `scripts/resolve-environment.sh`: read-only list and identifier resolver.
120
121
  - `scripts/poll-deploy-status.sh`: read-only status poller. Reads the Simple Deploy endpoint and `DevopsRequestInfo`, and reports component errors on failure.
122
+ - `scripts/widget.sh`: Operation C, Steps 2 and 5, only when the `render_widget` tool is available. Fills a card from `assets/widgets/` with `scripts/fill-widget.jq`, checks it with `scripts/card-policy.jq`, and prints `CARD_JSON <json>` or `CARD_UNAVAILABLE <reason>`. Makes no API call.
123
+ - `assets/widgets/<name>/`: the HXL chat cards (`connect-sign-in`, `connect-connected`), each a tile tree `<name>.json` and the `schema.json` of its values.
@@ -0,0 +1,65 @@
1
+ {
2
+ "definition": "tile/widget",
3
+ "children": [
4
+ {
5
+ "definition": "tile/container",
6
+ "attributes": {
7
+ "id": "dx-lifecycle-center--connect-connected--v1",
8
+ "label": "Lifecycle Center connection"
9
+ },
10
+ "children": [
11
+ {
12
+ "definition": "tile/column",
13
+ "attributes": {
14
+ "gap": "sm"
15
+ },
16
+ "children": [
17
+ {
18
+ "definition": "tile/row",
19
+ "attributes": {
20
+ "gap": "sm",
21
+ "align": "center",
22
+ "isWrapped": true
23
+ },
24
+ "children": [
25
+ {
26
+ "definition": "tile/text",
27
+ "attributes": {
28
+ "text": "Connected to Lifecycle Center",
29
+ "variant": "h3"
30
+ }
31
+ },
32
+ {
33
+ "definition": "tile/badge",
34
+ "attributes": {
35
+ "label": "Connected",
36
+ "variant": "success"
37
+ }
38
+ }
39
+ ]
40
+ },
41
+ {
42
+ "definition": "tile/text",
43
+ "attributes": {
44
+ "text": "Lifecycle Center org: {!$attrs.hubHost}",
45
+ "variant": "caption",
46
+ "color": "muted"
47
+ }
48
+ },
49
+ {
50
+ "definition": "tile/text",
51
+ "meta": {
52
+ "if": "{!$attrs.hasHubType}"
53
+ },
54
+ "attributes": {
55
+ "text": "Hub type: {!$attrs.hubTypeLabel}",
56
+ "variant": "caption",
57
+ "color": "muted"
58
+ }
59
+ }
60
+ ]
61
+ }
62
+ ]
63
+ }
64
+ ]
65
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "type": "object",
3
+ "title": "Connected to Lifecycle Center",
4
+ "description": "Connected card: which Lifecycle Center org the source org now calls, and its hub type when known.",
5
+ "properties": {
6
+ "attributes": {
7
+ "lightning:type": "lightning__objectType",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "hubHost",
11
+ "hasHubType",
12
+ "hubTypeLabel"
13
+ ],
14
+ "properties": {
15
+ "hubHost": {
16
+ "lightning:type": "lightning__textType",
17
+ "title": "Lifecycle Center org host",
18
+ "description": "The calloutUrl host, without https://."
19
+ },
20
+ "hasHubType": {
21
+ "lightning:type": "lightning__booleanType",
22
+ "title": "Show the hub type line"
23
+ },
24
+ "hubTypeLabel": {
25
+ "lightning:type": "lightning__textType",
26
+ "title": "Hub type",
27
+ "description": "Core or Managed package."
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "definition": "tile/widget",
3
+ "children": [
4
+ {
5
+ "definition": "tile/container",
6
+ "attributes": {
7
+ "id": "dx-lifecycle-center--connect-sign-in--v1",
8
+ "label": "Lifecycle Center connection"
9
+ },
10
+ "children": [
11
+ {
12
+ "definition": "tile/text",
13
+ "attributes": {
14
+ "text": "Sign in to Lifecycle Center",
15
+ "variant": "h3"
16
+ }
17
+ },
18
+ {
19
+ "definition": "tile/spacer",
20
+ "attributes": {
21
+ "size": "sm"
22
+ }
23
+ },
24
+ {
25
+ "definition": "tile/text",
26
+ "attributes": {
27
+ "text": "Sign in to your Lifecycle Center org as a user with the DevOps Center User permission set, allow access, and confirm access when your working org asks. Then come back here and reply done."
28
+ }
29
+ },
30
+ {
31
+ "definition": "tile/spacer",
32
+ "attributes": {
33
+ "size": "md"
34
+ }
35
+ },
36
+ {
37
+ "definition": "tile/button",
38
+ "attributes": {
39
+ "label": "Connect to Lifecycle Center org",
40
+ "variant": "primary",
41
+ "actions": {
42
+ "click": [
43
+ {
44
+ "definition": "action/openLink",
45
+ "attributes": {
46
+ "url": "{!$attrs.signInUrl}",
47
+ "target": "_blank"
48
+ }
49
+ }
50
+ ]
51
+ }
52
+ }
53
+ }
54
+ ]
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "object",
3
+ "title": "Connect to Lifecycle Center org",
4
+ "description": "Sign-in card: a heading, the steps to follow, and one button that opens the Lifecycle Center sign-in page in a new tab.",
5
+ "properties": {
6
+ "attributes": {
7
+ "lightning:type": "lightning__objectType",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "signInUrl"
11
+ ],
12
+ "properties": {
13
+ "signInUrl": {
14
+ "lightning:type": "lightning__multilineTextType",
15
+ "title": "Sign-in URL",
16
+ "description": "The redirectUrl from the setupNamedCredential POST after the &amp; fix, unmodified."
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
@@ -9,7 +9,7 @@ Worked prompts, grouped by operation (`SKILL.md`, Operations). Listing, status c
9
9
  **A1. "Show the list of connected orgs I can deploy to."**
10
10
 
11
11
  ```bash
12
- bash scripts/resolve-environment.sh my-dev-org
12
+ bash <skill_dir>/scripts/resolve-environment.sh my-dev-org
13
13
  ```
14
14
 
15
15
  Reply with only the table and the closing sentence (`references/list-orgs.md`, section 4). The Lifecycle Center org is not in it and is not mentioned.
@@ -79,7 +79,7 @@ Connected (Step 5):
79
79
  > |---|---|---|
80
80
  > | `mydomain--qa.sandbox.my.salesforce.com` | Sandbox | Ready to deploy to |
81
81
 
82
- The Lifecycle Center org uses the same two layouts with its own heading, button text, and a Hub type column.
82
+ The Lifecycle Center org uses the same two layouts with its own heading, button text, and a Hub type column. When the `render_widget` tool is available, it shows them as cards instead (C7).
83
83
 
84
84
  ---
85
85
 
@@ -111,6 +111,20 @@ Make no API call. Ask: "Do you mean the Lifecycle Center org, or a different org
111
111
 
112
112
  Say it is the Lifecycle Center hub, kept separate from deploy targets, and is never part of the deploy list.
113
113
 
114
+ **C7. "Connect the Lifecycle Center org", in a chat that has the `render_widget` tool.**
115
+
116
+ 1. Check the credential and, after confirming, create it as in C1. With the `redirectUrl` from the POST after the `&amp;` fix, run:
117
+
118
+ ```bash
119
+ bash <skill_dir>/scripts/widget.sh connect-sign-in '{"signInUrl":"https://<dev-org-host>/services/oauth2/authorize?..."}'
120
+ ```
121
+
122
+ It prints `CARD_JSON {"nodes":{"definition":"tile/widget","children":[...]}}`.
123
+ 2. Call `render_widget` once with the JSON after `CARD_JSON`, exactly as printed, and write no other text about the sign-in. The chat shows a **Sign in to Lifecycle Center** card with the steps and a **Connect to Lifecycle Center org** button.
124
+ 3. After **done**, run Steps 3 to 5. The status check passes and the type call answers Core, so run `bash <skill_dir>/scripts/widget.sh connect-connected '{"hubHost":"<hub-host>","hasHubType":true,"hubTypeLabel":"Core"}'` and call `render_widget` once with its JSON. The card reads "Connected to Lifecycle Center", the org host, and "Hub type: Core".
125
+
126
+ If `widget.sh` prints `CARD_UNAVAILABLE <reason>` or fails, or `render_widget` answers `{rendered: false, reason}`, use the Markdown layouts of B6 in hub form instead.
127
+
114
128
  ---
115
129
 
116
130
  ## D. Deploy
@@ -118,7 +132,7 @@ Say it is the Lifecycle Center hub, kept separate from deploy targets, and is ne
118
132
  **D1. "Deploy AccountService to https://mydomain--mysandbox.sandbox.my.salesforce.com."**
119
133
 
120
134
  ```bash
121
- bash scripts/resolve-environment.sh my-dev-org https://mydomain--mysandbox.sandbox.my.salesforce.com
135
+ bash <skill_dir>/scripts/resolve-environment.sh my-dev-org https://mydomain--mysandbox.sandbox.my.salesforce.com
122
136
  ```
123
137
 
124
138
  - `matched` and `selectable`: confirm the row back with name, URL, and org id, build the request, show the Step 4 confirmation, then submit.
@@ -143,7 +157,7 @@ Make no API call. Ask one question: which components to deploy. Then ask for the
143
157
  State what you will validate, then submit with `"isCheckDeploy": true` (`references/request-body.md`), then:
144
158
 
145
159
  ```bash
146
- bash scripts/poll-deploy-status.sh <requestId> my-dev-org 10 100
160
+ bash <skill_dir>/scripts/poll-deploy-status.sh <requestId> my-dev-org 10 100
147
161
  # Exit codes: 0 succeeded, 2 failed or not found, 3 timeout, 1 usage or call error (4 only with --once)
148
162
  ```
149
163
 
@@ -154,13 +168,13 @@ On success, report the validation id from `metadata.deployId` and offer a quick
154
168
  Skip the component and target steps. Poll once:
155
169
 
156
170
  ```bash
157
- bash scripts/poll-deploy-status.sh --once <requestId> my-dev-org
171
+ bash <skill_dir>/scripts/poll-deploy-status.sh --once <requestId> my-dev-org
158
172
  # Exit 4 means still processing: report the status and step
159
173
  ```
160
174
 
161
175
  **D9. The deploy takes more than 2 minutes.**
162
176
 
163
- The poll exits `3`. Reply: "Your deploy is still running. Request id: `<requestId>`. Send me this id and I'll check its status." Stop polling. When the user sends the id, run `bash scripts/poll-deploy-status.sh --once <requestId> my-dev-org` and report the status in plain language.
177
+ The poll exits `3`. Reply: "Your deploy is still running. Request id: `<requestId>`. Send me this id and I'll check its status." Stop polling. When the user sends the id, run `bash <skill_dir>/scripts/poll-deploy-status.sh --once <requestId> my-dev-org` and report the status in plain language.
164
178
 
165
179
  **D8. The user gives only an id starting `0Af`.**
166
180
 
@@ -89,7 +89,7 @@ This step **requires a human** (authorization code with PKCE, stored per user).
89
89
 
90
90
  > **Connect `<name>`**
91
91
  >
92
- > **[Sign in to `<name>` →](<redirectUrl>)**
92
+ > **[Sign in to `<name>` →]({{redirectUrl}})**
93
93
  >
94
94
  > 1. Sign in with the user DX Inspector should act as, and approve access.
95
95
  > 2. Come back here and reply **done**.
@@ -98,8 +98,19 @@ This step **requires a human** (authorization code with PKCE, stored per user).
98
98
 
99
99
  Hub mode uses the same layout with the heading **Connect the Lifecycle Center org** and the button text **Connect to Lifecycle Center org →**.
100
100
 
101
+ **Hub mode, as a card.** Only when the `render_widget` tool is available. Without it, use the layout above and skip this. Run, with the `redirectUrl` after the `&amp;` fix, unmodified:
102
+
103
+ ```bash
104
+ bash <skill_dir>/scripts/widget.sh connect-sign-in '{"signInUrl":"<redirectUrl>"}'
105
+ ```
106
+
107
+ It prints one line. The card has the heading **Sign in to Lifecycle Center**, the steps (sign in as a user with the **DevOps Center User** permission set, allow access, confirm access in the working org, then reply **done**), and a **Connect to Lifecycle Center org** button that opens the URL in a new tab.
108
+
109
+ - `CARD_JSON <json>`: call `render_widget` once with `<json>` as its arguments, exactly as printed. The card holds the heading, the steps, and the link, so write no other text about the sign-in. Never put the card JSON or the URL in your message.
110
+ - `CARD_UNAVAILABLE <reason>`, any other output or an error, or `render_widget` answers `{rendered: false, reason}`: use the layout above. Never edit the URL or the card JSON to make a card fit.
111
+
101
112
  Rules for the link:
102
- - Use the full `redirectUrl` after the `&amp;` fix, unmodified, as the Markdown link, and again in the "Link not working?" line. Show the sign-in once; do not repeat it in other words.
113
+ - Use the full `redirectUrl` after the `&amp;` fix, unmodified, as the Markdown link, and again in the "Link not working?" line. Show the sign-in once, as the layout or as the card; do not repeat it in other words.
103
114
  - Only the newest link works. Each new Step 1 run (hub) or `GET /connect/devops/environment/<id>` (deploy) replaces the previous one, so never run one while the user is still signing in, and never show an older link again. If the user reports it expired or failed, get a fresh one the same way.
104
115
  - The user should open it in a browser that is signed in to the dev org as the same user the CLI uses (the final confirmation happens on the dev org). Otherwise the browser lands on that org's login page: tell them to sign in there, then use the link again.
105
116
  - Right after showing the layout, wait for the user to reply **done**. Do not run other steps in between.
@@ -170,6 +181,14 @@ Success returns `{"namedCredentialName": "...", "calloutUrl": "https://<org>.my.
170
181
  > | `<host of calloutUrl>` | Core or Managed package | Connected |
171
182
 
172
183
  Say "Sandbox" for a scratch org too. If the status check in item 1 did not return `Configured`, do not show this layout: say the sign-in is not complete and offer a fresh link.
184
+
185
+ **Hub mode, as a card.** Only when item 1 passed and the `render_widget` tool is available. Without it, use the layout above and skip this. Run, with the `calloutUrl` host and the hub type from item 2:
186
+
187
+ ```bash
188
+ bash <skill_dir>/scripts/widget.sh connect-connected '{"hubHost":"<host of calloutUrl>","hasHubType":true,"hubTypeLabel":"<Core or Managed package>"}'
189
+ ```
190
+
191
+ When the type call was skipped or unknown, send `"hasHubType":false,"hubTypeLabel":""`. On `CARD_JSON <json>`, call `render_widget` once with `<json>` as its arguments, exactly as printed, in place of the layout above; the card shows the org host and the hub type, so do not repeat them in text. On `CARD_UNAVAILABLE <reason>`, any other output or an error, or `{rendered: false, reason}`, use the layout above.
173
192
  4. **Deploy mode:** re-run the environment lookup (`list-orgs.md`) and confirm the row with the `id` from Step 1 is listed, `selectable`, with its `NamedCredential`. Carry that `id` and `namedCredential` forward. If it is missing, do not deploy and do not invent an id; report that the credential is connected but the row was not found.
174
193
  5. **If this connect started from a deploy request** (`deploy.md`, Step 2): tell the user in one sentence that `<name>` is connected and that you are continuing the deploy of the components they gave. Then go to `deploy.md`, Step 3 and Step 4. The deploy confirmation is theirs to give; do not submit anything before it. If the connect did not start from a deploy, end here and do not offer anything beyond the result.
175
194
 
@@ -93,7 +93,7 @@ Read `response.requestId`. If it is absent, the call failed: use `references/err
93
93
  Polling is automatic and read-only. Every check reads **two sources**, and a terminal state from **either** one ends it: the Simple Deploy status endpoint (live `step`, `metadata.deployId`) and the `DevopsRequestInfo` record for the `requestId` (`Status` is `SUCCESS` or `ERROR`; it is the same record commit polling uses).
94
94
 
95
95
  ```bash
96
- bash scripts/poll-deploy-status.sh <requestId> <source-org-alias> 10 100
96
+ bash <skill_dir>/scripts/poll-deploy-status.sh <requestId> <source-org-alias> 10 100
97
97
  ```
98
98
 
99
99
  Checks come at 3 s, then 5 s, then every 10 s, for at most **100 seconds**, about 2 minutes in all. Set the shell tool timeout to at least 180 seconds so the run is not killed before it exits. Progress lines (`status=… step=… request-info=…`) go to stderr; relay the current step to the user while waiting. Never say the deploy is "still waiting" after the script has printed a result.
@@ -127,7 +127,7 @@ On timeout (exit `3`, `outcome` `TIMEOUT`, about 2 minutes), stop polling and te
127
127
 
128
128
  Example: "Your deploy to `<target>` hasn't reported a final status after 2 minutes. It was at `DEPLOY_METADATA` and may still be running. Request token: `<requestId>`. Deployment id: `<deployId>`. Send me the request token any time and I'll check it, or look up the deployment id in `<target>` under Setup → Deployment Status." Never resubmit, and do not keep polling.
129
129
 
130
- For a one-off check, put `--once` **first**: `bash scripts/poll-deploy-status.sh --once <requestId> <source-org-alias>`. It exits `4` while the request is still processing: report the current `step` and do not poll again unless the user asks. With `--once` there is no grace period, so `NOT_FOUND` right after a submit may be transient: say the request is not visible yet and check again shortly, not that it failed.
130
+ For a one-off check, put `--once` **first**: `bash <skill_dir>/scripts/poll-deploy-status.sh --once <requestId> <source-org-alias>`. It exits `4` while the request is still processing: report the current `step` and do not poll again unless the user asks. With `--once` there is no grace period, so `NOT_FOUND` right after a submit may be transient: say the request is not visible yet and check again shortly, not that it failed.
131
131
 
132
132
  If the user gives a `requestId` to check (also when they come back with the id from a timeout), skip Steps 1 to 5 and check it once with `--once`, using the source org alias. If the user asks for the status without an id, use the `requestId` from earlier in this conversation; if there is none, ask for it. Then report as in Step 7.
133
133
 
@@ -7,7 +7,7 @@ The targets are the DX Inspector environments, **not** the orgs authorized on th
7
7
  ## 1. Run the resolver
8
8
 
9
9
  ```bash
10
- bash scripts/resolve-environment.sh <source-org-alias> [identifier]
10
+ bash <skill_dir>/scripts/resolve-environment.sh <source-org-alias> [identifier]
11
11
  ```
12
12
 
13
13
  `<source-org-alias>` is the alias the user named, else the default org from `sf org display --json`. Pass `identifier` exactly as the user gave it. It accepts:
@@ -0,0 +1,71 @@
1
+ # Check a filled widget tree against the chat-card v1 rules before widget.sh prints it.
2
+ # Prints nothing when the card may be shown, otherwise one line, "<reason>: <detail>".
3
+ # root a bare tile/widget with one tile/container child, id "<skill>--<card>--v<N>"
4
+ # tiles only the tiles in allowed; a node has only definition, attributes and children
5
+ # action only a button has actions: one click, either action/openLink (an allowed URL,
6
+ # target _blank) or action/sendMessage (literal text, 1-2000 characters)
7
+ # url https, a host that is or ends in salesforce.com, force.com or salesforce.mil, no spaces,
8
+ # no "&amp;" left in it
9
+ # table 1-6 plain columns (no link or typed columns), at most 25 rows of text cells
10
+ # secret no session id, access or refresh token, OAuth code or bearer token anywhere
11
+ # expr no "{!" anywhere: a card is literal, nothing is left for a renderer to evaluate
12
+ # limits at most 80 nodes and depth 8 (widget.sh checks the size)
13
+ # Usage: jq -r -f card-policy.jq <filled tree> (add --arg all 1 to list every problem)
14
+ def allowed: ["tile/container", "tile/column", "tile/row", "tile/text", "tile/badge", "tile/icon",
15
+ "tile/separator", "tile/spacer", "tile/table", "tile/list", "tile/listItem", "tile/callout",
16
+ "tile/progress", "tile/code", "tile/button"];
17
+ def allowed_url: type == "string" and length <= 2000 and (test("\\s") | not) and (contains("&amp;") | not)
18
+ and test("^https://([A-Za-z0-9-]+\\.)*(salesforce\\.com|force\\.com|salesforce\\.mil)(:[0-9]+)?([/?#]|$)");
19
+ def secret: test("[?&#](sid|access_token|refresh_token|code)=|00D[A-Za-z0-9]{12,15}![A-Za-z0-9._-]{16,}|Bearer\\s+[A-Za-z0-9._~+/-]{16,}"; "i");
20
+ def nodes: .children[]? | recurse(.children[]?);
21
+ def depth: if ((.children // []) | length) == 0 then 0 else 1 + ([.children[] | depth] | max) end;
22
+ def action_problems:
23
+ if .attributes.actions == null then
24
+ if .definition == "tile/button" then "action: a button needs attributes.actions.click" else empty end
25
+ elif .definition != "tile/button" then "action: only tile/button may have actions"
26
+ elif (.attributes.actions | type) != "object" or (.attributes.actions | keys) != ["click"]
27
+ or (.attributes.actions.click | type) != "array" or (.attributes.actions.click | length) != 1
28
+ then "action: a button needs exactly one click action"
29
+ else .attributes.actions.click[0] as $a
30
+ | if $a.definition == "action/openLink" then
31
+ if ($a.attributes.url | allowed_url) | not then "url: an openLink URL is not https on a Salesforce host, or still has &amp;"
32
+ elif $a.attributes.target != "_blank" then "action: openLink must open a new tab (_blank)"
33
+ else empty end
34
+ elif $a.definition == "action/sendMessage" then
35
+ if ($a.attributes.content | type) != "string" or ($a.attributes.content | length) < 1
36
+ or ($a.attributes.content | length) > 2000
37
+ then "action: sendMessage needs 1-2000 characters of text" else empty end
38
+ else "action: \($a.definition) is not allowed" end
39
+ end;
40
+ def table_problems:
41
+ if .definition != "tile/table" then empty else .attributes as $t
42
+ | (if ($t.columns | type) != "array" or ($t.columns | length) < 1 or ($t.columns | length) > 6
43
+ then "table: 1-6 columns" else empty end),
44
+ (if [$t.columns[]? | select(type != "object" or .columnType != null)] != []
45
+ then "table: no link or typed columns" else empty end),
46
+ (if ($t.rows | type) != "array" or ($t.rows | length) > 25 then "table: at most 25 rows" else empty end),
47
+ (if [$t.rows[]? | select(type != "object" or ([.[] | select(type != "string")] != []))] != []
48
+ then "table: every row is an object of text cells" else empty end)
49
+ end;
50
+ def node_problems:
51
+ if type != "object" then "tiles: a child is not a tile"
52
+ else
53
+ (keys - ["definition", "attributes", "children"]) as $extra
54
+ | (if $extra != [] then "tiles: \(.definition) has \($extra | join(", "))" else empty end),
55
+ (.definition as $d | if any(allowed[]; . == $d) then empty else "tiles: \($d // "a node with no definition") is not allowed" end),
56
+ action_problems, table_problems
57
+ end;
58
+
59
+ [ (if .definition != "tile/widget" or (keys - ["definition", "children"]) != []
60
+ or (.children | length) != 1 or .children[0].definition != "tile/container"
61
+ or ((.children[0].attributes.id // "") | test("^[a-z0-9-]+--[a-z0-9-]+--v[0-9]+$") | not)
62
+ then "root: a bare tile/widget with one tile/container, id <skill>--<card>--v<N>" else empty end),
63
+ (nodes | node_problems),
64
+ ([nodes] | length | if . > 80 then "limits: \(.) nodes, more than 80" else empty end),
65
+ (depth | if . > 8 then "limits: depth \(.), more than 8" else empty end),
66
+ ([.. | strings | select(secret)] | length | if . > 0 then "secret: \(.) value(s) look like a session id or token" else empty end),
67
+ ([.. | strings | select(test("\\{!"))] | length | if . > 0 then "expr: \(.) value(s) contain {!" else empty end)
68
+ ]
69
+ | if length == 0 then empty
70
+ elif $ARGS.named.all != null then join("; ")
71
+ else .[0] + (if length > 1 then " (and \(length - 1) more)" else "" end) end
@@ -0,0 +1,29 @@
1
+ # Fill an HXL widget template (<name>.json) with the values in $attrs, the way
2
+ # mosaic-json-core evaluates the same bindings, so the result has no expressions left:
3
+ # "{!$attrs.k}" as the whole string -> the value itself, any JSON type
4
+ # "... {!$attrs.k} ..." inside a string -> the value as text
5
+ # "meta": {"if": "{!$attrs.k}"} -> the node stays only when k is true
6
+ # Any other expression or meta key, a missing attr, or a "{!" in a value is an error.
7
+ # A v68.0 envelope ({"type": "lightning__agentforceWidget", "contentBody": {"widgetBody": ...}})
8
+ # is unwrapped first, so the result is always the bare tile/widget tree.
9
+ # Usage: jq -c --argjson attrs '<json object>' -f fill-widget.jq <name>.json
10
+ def binding: "\\{!\\$attrs\\.(?<k>[A-Za-z0-9_]+)\\}";
11
+ def attr($k): if $attrs | has($k) then $attrs[$k] else error("missing attr: \($k)") end;
12
+ def fill:
13
+ if test("^" + binding + "$") then attr(capture("^" + binding + "$").k)
14
+ else gsub(binding; attr(.k) | tostring) end;
15
+ def keep:
16
+ if (.meta | type) != "object" then true
17
+ elif (.meta | keys) != ["if"] then error("unsupported meta: \(.meta | keys | join(","))")
18
+ elif (.meta.if | type) == "string" then (.meta.if | fill) == true
19
+ else .meta.if == true end;
20
+ def prune: if (.children | type) == "array" then .children |= map(select(keep) | prune) else . end;
21
+
22
+ (if .type == "lightning__agentforceWidget" then .contentBody.widgetBody else . end)
23
+ | if [.. | strings | select(gsub(binding; "") | test("\\{!"))] != [] then error("unsupported expression in template")
24
+ elif .meta != null then error("meta is not allowed on the root")
25
+ else . end
26
+ | prune
27
+ | walk(if type == "object" and has("definition") then del(.meta) else . end)
28
+ | walk(if type == "string" then fill else . end)
29
+ | if [.. | strings | select(test("\\{!"))] != [] then error("a value contains {!") else . end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # Fill one of this skill's HXL widgets (assets/widgets/<name>/<name>.json), check it
3
+ # with card-policy.jq, and print one line for the chat:
4
+ # CARD_JSON {"nodes": <tree>} call render_widget once with exactly this JSON as its arguments
5
+ # CARD_UNAVAILABLE <reason> show no card; give the same facts in text instead
6
+ # Usage: widget.sh <name> '<attrs json>' (connect-org.md, Steps 2 and 5, hub mode)
7
+ # Always exits 0: the card is optional, the facts the other scripts print are not.
8
+ set -uo pipefail
9
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ NAME="${1:-}" ATTRS="${2:-}"
11
+ MAX_BYTES="${CARD_MAX_BYTES:-8192}"
12
+ TEMPLATE="$HERE/../assets/widgets/$NAME/$NAME.json"
13
+ unavailable() { echo "CARD_UNAVAILABLE $1"; exit 0; }
14
+ if ! [[ "$NAME" =~ ^[a-z0-9-]+$ ]] || [ ! -f "$TEMPLATE" ]; then
15
+ unavailable "template: no widget named '$NAME'"
16
+ fi
17
+ if ! TREE=$(jq -c --argjson attrs "$ATTRS" -f "$HERE/fill-widget.jq" "$TEMPLATE" 2>&1); then
18
+ TREE=${TREE%%$'\n'*}
19
+ unavailable "fill: ${TREE##*): }"
20
+ fi
21
+ if ! PROBLEM=$(printf '%s' "$TREE" | jq -r -f "$HERE/card-policy.jq" 2>/dev/null); then
22
+ unavailable "policy: the check failed"
23
+ fi
24
+ [ -z "$PROBLEM" ] || unavailable "$PROBLEM"
25
+ ARGS=$(printf '%s' "$TREE" | jq -c '{nodes: .}')
26
+ BYTES=$(printf '%s' "$ARGS" | wc -c | tr -d ' ')
27
+ [ "$BYTES" -le "$MAX_BYTES" ] || unavailable "size: $BYTES bytes, more than $MAX_BYTES"
28
+ echo "CARD_JSON $ARGS"