@salesforce/afv-skills 1.44.0 → 1.45.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 (97) hide show
  1. package/package.json +1 -1
  2. package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +72 -0
  3. package/skills/consumer-goods-rtr-datacloud-export-configure/references/inputs-and-namespace.md +38 -0
  4. package/skills/consumer-goods-rtr-datacloud-export-configure/references/procedure.md +158 -0
  5. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/detect-namespace.js +86 -0
  6. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/render-apex.js +64 -0
  7. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/resolve-id-by-name.js +47 -0
  8. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/sf-rest.js +171 -0
  9. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/soql-escape.js +26 -0
  10. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/upsert-report-config.apex +51 -0
  11. package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/upsert-system-setting.apex +21 -0
  12. package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +74 -0
  13. package/skills/consumer-goods-tpe-dashboard-configure/references/phases-1-6.md +112 -0
  14. package/skills/consumer-goods-tpe-dashboard-configure/references/phases-7-12.md +157 -0
  15. package/skills/consumer-goods-tpe-dashboard-configure/scripts/find-failure-reason.js +132 -0
  16. package/skills/consumer-goods-tpe-dashboard-configure/scripts/poll-status.js +116 -0
  17. package/skills/consumer-goods-tpe-dashboard-configure/scripts/render-apex.js +64 -0
  18. package/skills/consumer-goods-tpe-dashboard-configure/scripts/run-data-transform.js +121 -0
  19. package/skills/consumer-goods-tpe-dashboard-configure/scripts/schedule-business-period-export.apex +27 -0
  20. package/skills/consumer-goods-tpe-dashboard-configure/scripts/sf-rest.js +171 -0
  21. package/skills/consumer-goods-tpe-dashboard-configure/scripts/soql-escape.js +25 -0
  22. package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +141 -0
  23. package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/references/payload-shapes.md +447 -0
  24. package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/references/procedure.md +263 -0
  25. package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/scripts/clone-tpe-dashboards.js +537 -0
  26. package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/scripts/sf-rest.js +195 -0
  27. package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +157 -0
  28. package/skills/consumer-goods-tpe-datakit-deploy/scripts/detect-namespace.js +86 -0
  29. package/skills/consumer-goods-tpe-datakit-deploy/scripts/download-static-resource.js +151 -0
  30. package/skills/consumer-goods-tpe-datakit-deploy/scripts/extract-crm-field-permissions.js +115 -0
  31. package/skills/consumer-goods-tpe-datakit-deploy/scripts/sf-rest.js +109 -0
  32. package/skills/consumer-goods-tpe-datakit-deploy/scripts/update-field-permissions.js +433 -0
  33. package/skills/service-catalog-template-coordinate/SKILL.md +263 -0
  34. package/skills/service-catalog-template-coordinate/examples/output-templates.md +44 -0
  35. package/skills/service-catalog-template-coordinate/references/mcp-invocation.md +183 -0
  36. package/skills/service-catalog-template-coordinate/references/operations.md +230 -0
  37. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/SKILL.md +243 -0
  38. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/cli-invocation.md +205 -0
  39. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/helper-contracts.md +236 -0
  40. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/permset-topology.md +132 -0
  41. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-activated-agents.mjs +106 -0
  42. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-agent-access-state.mjs +113 -0
  43. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-assignment-state.mjs +99 -0
  44. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-platform-permset-availability.mjs +155 -0
  45. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/gate-unified-catalog-tiers.mjs +100 -0
  46. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/rank-candidate-users.mjs +95 -0
  47. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/resolve-target-user.mjs +86 -0
  48. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +44 -23
  49. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +33 -9
  50. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +17 -18
  51. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +3 -1
  52. package/skills/service-itsm-agentic-setup-configure/SKILL.md +20 -12
  53. package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +73 -5
  54. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -7
  55. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +45 -33
  56. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +8 -6
  57. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +10 -10
  58. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +114 -56
  59. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +33 -17
  60. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +9 -3
  61. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -7
  62. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +43 -32
  63. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +6 -4
  64. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +10 -10
  65. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +106 -55
  66. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +27 -13
  67. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +9 -3
  68. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +159 -161
  69. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +51 -0
  70. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +1 -1
  71. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +120 -0
  72. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +28 -5
  73. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +19 -1
  74. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +350 -30
  75. package/skills/service-itsm-channels-coordinate/SKILL.md +80 -213
  76. package/skills/service-itsm-slack-itservice-configure/SKILL.md +363 -0
  77. package/skills/service-itsm-slack-itservice-configure/references/connect-agentforce-to-slack.md +159 -0
  78. package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +88 -0
  79. package/skills/service-itsm-slack-itservice-configure/references/manage-user-access.md +117 -0
  80. package/skills/service-itsm-slack-itservice-configure/references/record-visibility.md +78 -0
  81. package/skills/service-itsm-slack-itservice-configure/references/site-membership-verification.md +126 -0
  82. package/skills/service-itsm-slack-itservice-configure/scripts/classify-user-access.mjs +167 -0
  83. package/skills/service-itsm-teams-configure/SKILL.md +50 -47
  84. package/skills/service-itsm-teams-configure/references/azure-credential-population.md +42 -28
  85. package/skills/service-itsm-teams-configure/references/gotchas.md +1 -2
  86. package/skills/service-itsm-teams-coordinate/SKILL.md +22 -18
  87. package/skills/service-itsm-teams-coordinate/examples/output-templates.md +12 -9
  88. package/skills/service-itsm-teams-itdesk-configure/SKILL.md +60 -44
  89. package/skills/service-itsm-teams-itservice-configure/SKILL.md +56 -70
  90. package/skills/service-catalog-template-deploy/SKILL.md +0 -310
  91. package/skills/service-catalog-template-deploy/references/cli-invocation.md +0 -258
  92. package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +0 -164
  93. package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +0 -94
  94. package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +0 -331
  95. package/skills/service-catalog-template-search/SKILL.md +0 -212
  96. package/skills/service-catalog-template-search/references/cli-invocation.md +0 -128
  97. package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +0 -205
@@ -48,8 +48,8 @@ Microsoft Teams. Every operation dispatches through **headless-360**.
48
48
  afterward; explaining why the direct org-preference PATCH route fails and why this route
49
49
  works instead; disabling the feature if requested; giving the user step-by-step instructions
50
50
  for the Azure/Entra app registration (Step 4a) since no Salesforce API can perform that part;
51
- once the user provides the resulting Client ID/Tenant ID (in chat) and the Client Secret (via the
52
- `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file, never in chat), writing them
51
+ once the user provides the resulting Client ID/Tenant ID (in chat) and the Client Secret (written
52
+ to a gitignored secret file via the copy-paste command in Step 4a, never in chat), writing them
53
53
  directly into the `MSTeamsSetupClientCredentialsEC` Named Credential via API — this
54
54
  Salesforce-side write is always automated by this skill, never deferred back to the user;
55
55
  registering the Experience Cloud site as the Teams "preferred site" extension via
@@ -160,13 +160,12 @@ inaccessible via direct PATCH — is now enabled as a side effect of the feature
160
160
  ### Step 4 — Report *interim* status (setup is NOT complete yet)
161
161
 
162
162
  Report feature status and whether `ITSMTeamsEnabled` reads `true` — but **frame this as progress,
163
- not completion.** Enabling the Go feature is only the first half. The integration is **not
164
- functional** until the Microsoft Entra app is registered, its credentials are written into the
165
- Named Credential + Auth Provider, and admin consent is granted (Step 4a). Do **not** call this an
166
- "optional manual tail," do **not** mark Teams "Done"/"configured"/"complete," and do **not** hand
167
- back to any coordinator as done. State plainly: *"The Salesforce feature is enabled; Teams
168
- integration is not yet complete — the required Microsoft Entra app registration comes next."* Then
169
- proceed directly into Step 4a. See the **Completion contract** below for what "complete" requires.
163
+ not completion.** Enabling the Go feature is only the first half; the integration is **not
164
+ functional** until the Microsoft Entra app is registered, its credentials are written into the Named
165
+ Credential + Auth Provider, and admin consent is granted (Step 4a). Do **not** mark Teams
166
+ "Done"/"complete" or hand back to a coordinator as done. State plainly: *"The Salesforce feature is
167
+ enabled; Teams integration is not yet complete — the Microsoft Entra app registration comes next."*
168
+ Then proceed into Step 4a. See the **Completion contract** below for what "complete" requires.
170
169
 
171
170
  ### Step 4a — Follow the Go page's own order: Create Entra app → Configure Named Credentials → Grant consent
172
171
 
@@ -182,26 +181,39 @@ order; do not skip ahead to Named Credentials before the Entra app exists, and d
182
181
  clicks and wait for them to provide the resulting values:
183
182
  - **portal.azure.com** → **Microsoft Entra ID** → **App registrations** → **New registration**.
184
183
  Name it something identifiable (e.g. `Salesforce ITSM Teams Integration`); single-tenant is
185
- fine unless the user's org spans multiple tenants; no redirect URI is needed for the
186
- client-credentials flow used here.
184
+ fine unless the user's org spans multiple tenants. Leave the redirect URI blank at creation —
185
+ the Delegated Graph permissions below require one, but it's added later as the Auth Provider
186
+ callback (Step 5; see `references/azure-credential-population.md`).
187
187
  - From the app's **Overview** page, note the **Application (client) ID** and **Directory
188
188
  (tenant) ID**.
189
189
  - **Certificates & secrets** → **New client secret** → copy the secret **value** immediately
190
190
  (unrecoverable after leaving the page).
191
- - **API permissions** → **Add a permission** → **Microsoft Graph** → **Application
192
- permissions** → add the Graph permissions this integration needs (at minimum
193
- `ChannelMessage.Send`, `Team.ReadBasic.All`, `Channel.ReadBasic.All`,
194
- `TeamworkAppSettings.ReadWrite.All` — confirm against the org's current Teams for Employee
195
- Service documentation, since required scopes can change between releases).
196
- - Provide the credentials **without exposing the secret in chat**: the **Client ID** and
197
- **Tenant ID** are non-secret identifiers and may be given in the conversation, but the
198
- **Client Secret is a confidential credential — NEVER ask for it in chat and never accept it
199
- there.** The user places the secret in the `TEAMS_ENTRA_CLIENT_SECRET` environment variable
200
- (or a gitignored secret file whose path they give you); you read it from that source at write
201
- time and never print, echo, or log its value.
191
+ - **API permissions** → **Add a permission** → **Microsoft Graph** → **Delegated
192
+ permissions** → add all 17 below, then click **Grant admin consent** so every row reads
193
+ *Granted*. These are **Delegated** (not Application) — verified working set:
194
+ `Channel.Create`, `Channel.ReadBasic.All`, `ChannelMember.Read.All`,
195
+ `ChannelMember.ReadWrite.All`, `ChannelMessage.Edit`, `ChannelMessage.Read.All`,
196
+ `ChannelMessage.ReadWrite`, `ChannelMessage.Send`, `Team.Create`, `Team.ReadBasic.All`,
197
+ `Group.Read.All`, `Group.ReadWrite.All`, `openid`, `profile`, `email`, `offline_access`,
198
+ `User.Read`. Several require admin consent (*Admin consent required = Yes*), so the **Grant
199
+ admin consent** click is mandatory — ungranted consent-required rows make Teams calls fail
200
+ (see the AccessDenied gotcha). Do **not** add `TeamworkAppSettings.ReadWrite.All` (not in the
201
+ working set). Scopes can change between releases — if MS docs list more, add and re-grant.
202
+ - Provide the credentials **without exposing the secret in chat**: **Client ID** and **Tenant
203
+ ID** are non-secret and may be given in the conversation; the **Client Secret is confidential —
204
+ NEVER ask for it in chat.** Have the user write it to a **gitignored file**: substitute the
205
+ job/temp path for `<secret-file>` (e.g. `$CLAUDE_JOB_DIR/tmp/teams-secret`), then hand them exactly
206
+ this to copy-paste into the Claude Code prompt (secret Value, not the Secret ID, between the quotes):
207
+ ```bash
208
+ ! umask 077; printf '%s' 'PASTE-CLIENT-SECRET-HERE' > <secret-file> && echo written
209
+ ```
210
+ Keep the leading `!` — it runs the line in this session's Bash so the file persists. It prints
211
+ `written`; then read it from `<secret-file>` at write time (Step 5) and never echo or log it.
212
+ > **Note:** the `!`-prefix line is echoed into the chat transcript — if the secret shows up there,
213
+ > treat it as compromised and have the user rotate it in Azure after setup works.
202
214
  2. **Configure Setup Named Credentials** ("Go to Setup" button on the Go page — the manual
203
215
  equivalent of what this skill automates). **Once you have the Client ID / Tenant ID and the
204
- secret is available in the env var / file, do not tell the user to enter anything into Setup —
216
+ secret is available in the secret file, do not tell the user to enter anything into Setup —
205
217
  call the Named Credential APIs directly**, per "Populating `MSTeamsSetupClientCredentialsEC`
206
218
  given a user-supplied client ID/secret" under Step 5 below. **This same set of values must ALSO be written into the
207
219
  `microsoft_auth_provider` Auth Provider** (the inbound-SSO side, distinct from the outbound-Graph
@@ -225,7 +237,7 @@ order; do not skip ahead to Named Credentials before the Entra app exists, and d
225
237
 
226
238
  Everything the user does above (steps 1's Azure clicks and step 3's consent click) is their
227
239
  manual responsibility because no Salesforce API reaches Azure/Entra. Everything Salesforce-side —
228
- writing the supplied credential (secret read from the env var / secret file, never from chat) into
240
+ writing the supplied credential (secret read from the gitignored secret file, never from chat) into
229
241
  the Named Credential in step 2 — is this skill's job to automate; that division of labor is the
230
242
  entire point of this skill.
231
243
 
@@ -281,27 +293,18 @@ If this returns `400 UNKNOWN_EXCEPTION "...external credential \"MSTeamsSetupCli
281
293
  might not exist"`, the Azure/Entra step (Gotchas) has not been completed yet — this is not a bug
282
294
  in the call itself.
283
295
 
284
- If instead it returns `AccessDenied` (or `400 UNKNOWN_EXCEPTION "Exception while creating Teams
285
- extension: Unable to fetch tenant ID"`) **even after** the external credential shows
286
- `authenticationStatus: "Configured"`, the cause is almost always the **Azure app's Graph
287
- permissions being of type _Delegated_ rather than _Application_** (client-credentials token flow
288
- cannot use delegated-only permissions). This is a **fixable Azure/Entra misconfiguration, not a
289
- hard license wall** — verified live this session: the same call went from `AccessDenied` to
290
- `201 Success` (`com_sf_itsm_teams_config`) after two changes on the Azure side, with no license
291
- change:
292
-
293
- 1. In the Azure app registration → **API permissions**, ensure the Microsoft Graph permissions are
294
- the **Application** type (not Delegated), then click **"Grant admin consent"** for the tenant.
295
- 2. **Repopulate the credential** (see "Populating..." below) — re-provisioning or any feature
296
- re-enable can leave the EC/Auth Provider empty; a freshly-populated `MSTeamsSetupClientCredentialsEC`
297
- showing `authenticationStatus: "Configured"` is required at the moment of the retry.
298
-
299
- Retry Step 5 after both. Only treat this as a genuine org-license blocker (the `MsTeamsAppApiFamily`
300
- gotcha below) if the call **still** fails once Application-type Graph permissions + admin consent
301
- are confirmed and the credential is freshly `Configured`.
296
+ If instead it returns `AccessDenied` (or `400 UNKNOWN_EXCEPTION "...Unable to fetch tenant ID"`)
297
+ **even after** the EC shows `authenticationStatus: "Configured"`, the cause is almost always an
298
+ **incomplete Azure/Entra grant** — fixable, not a license wall (verified: same call went
299
+ `AccessDenied` → `201 Success` after these). Check, in order: (1) **admin consent not granted** —
300
+ several Step 4a scopes read *Admin consent required = Yes* and surface as `AccessDenied` until an
301
+ admin clicks **Grant admin consent**; confirm every row reads *Granted*. (2) **credential empty** —
302
+ a re-provision can empty the EC; it must read `Configured` at retry, so **repopulate** it. Retry
303
+ Step 5 after both. **Do not "fix" this by switching Delegated → Application** — the verified working
304
+ integration is Delegated + admin consent; flipping to Application diverges from the known-good setup.
302
305
 
303
306
  Once you have the Azure Client ID and Tenant ID (given in chat) and the Client Secret (read from the
304
- `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file — never requested in chat; Step 4a), do the
307
+ gitignored secret file written in Step 4a — never requested in chat), do the
305
308
  Salesforce-side writes yourself — do not tell the user to enter values in Setup. The full verified
306
309
  recipe (populating `MSTeamsSetupClientCredentialsEC`, populating the `microsoft_auth_provider` Auth
307
310
  Provider for inbound SSO via the Metadata API, matching the portal user's `Username` to the Microsoft
@@ -324,8 +327,8 @@ optional tail. Report **complete only when every item below is verified** (not m
324
327
  1. **Feature enabled** — `service-cloud-itsm-teams-integration` reads `ENABLED` and
325
328
  `ITSMTeamsEnabled` reads `true` (Steps 1–3).
326
329
  2. **Microsoft Entra app registered** — the user has completed Step 4a's Azure clicks and provided
327
- the Client ID and Tenant ID (in chat) with the Client Secret placed in the
328
- `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (never pasted in chat). Until they do, **stop
330
+ the Client ID and Tenant ID (in chat) with the Client Secret written to the gitignored secret
331
+ file via the Step 4a copy-paste command (never pasted in chat). Until they do, **stop
329
332
  and wait** — this is a hard gate; you cannot proceed past it, and you must not report completion
330
333
  around it.
331
334
  3. **Credentials populated (Salesforce-side, automated by this skill)** — `MSTeamsSetupClientCredentialsEC`
@@ -375,8 +378,8 @@ not instead of, the Step 2 feature-enable call if the user wants both Hubs.
375
378
  ## Gotchas
376
379
 
377
380
  The verified, load-bearing pitfalls (direct-PATCH 401, empty Auth Provider, Azure Web-vs-SPA
378
- redirect, Username=UPN handler, portal API-Enabled, static consent link, `MsTeamsAppApiFamily`
379
- 403 hard gate, version-prefix requirement, and more) are catalogued in
381
+ redirect, Username=UPN handler, portal API-Enabled, static consent link, version-prefix
382
+ requirement, and more) are catalogued in
380
383
  [`references/gotchas.md`](references/gotchas.md). Read it before reporting a step as failed or
381
384
  retrying an enablement guess.
382
385
 
@@ -2,19 +2,21 @@
2
2
 
3
3
  Reference for `service-itsm-teams-configure` Step 5. Once the org has an external credential named
4
4
  `MSTeamsSetupClientCredentialsEC` and the user has supplied their Azure **Client ID** and **Tenant
5
- ID** (non-secret identifiers, given in chat) and placed the **Client Secret** in the
6
- `TEAMS_ENTRA_CLIENT_SECRET` environment variable or a gitignored secret file (Step 4a — **never ask
7
- for the secret in chat**), these are the Salesforce-side writes that populate the outbound Graph
8
- credential, the inbound-SSO Auth Provider, and the portal-user access that make the Teams IT Service
9
- / IT Desk apps actually work. Read the secret from that env var / file at write time; never print,
10
- echo, or log its value, and never send the literal `$TEAMS_ENTRA_CLIENT_SECRET` token to an API —
11
- always resolve it to its actual value first (see the Secret-substitution note in Step 2). Do all of
12
- these yourself — the user's manual responsibility ends at the Azure admin center.
5
+ ID** (non-secret identifiers, given in chat) and written the **Client Secret** to a **gitignored
6
+ secret file** via the Step 4a copy-paste command (**never ask for the secret in chat**; do NOT use an
7
+ `export`-to-env-var route — an interactive `!`-prefix export runs in a different shell than the
8
+ agent's tool calls, so the value never reaches the agent), these are the Salesforce-side writes that
9
+ populate the outbound Graph credential, the inbound-SSO Auth Provider, and the portal-user access
10
+ that make the Teams IT Service / IT Desk apps actually work. Read the secret from that file at write
11
+ time (`cat <secret-file>` into an in-memory variable); never print, echo, or log its value, and never
12
+ send a literal `$TEAMS_ENTRA_CLIENT_SECRET` token to an API — always resolve it to its actual value
13
+ first (see the Secret-substitution note in Step 2). Do all of these yourself — the user's manual
14
+ responsibility ends at the Azure admin center.
13
15
 
14
16
  ## Populating `MSTeamsSetupClientCredentialsEC` given a user-supplied client ID/secret
15
17
 
16
18
  **Once the user supplies the Client ID and Tenant ID (in chat) and the Client Secret is available in
17
- the `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (Step 4a — never in chat), write them into
19
+ the gitignored secret file (Step 4a — never in chat), write them into
18
20
  Salesforce yourself via the calls below. Do not respond by telling the user to open Setup and enter
19
21
  the values manually — that defeats the purpose of this skill.** The user's manual responsibility
20
22
  ends at the Azure admin center (Step 4a); every Salesforce-side write, including this one, is this
@@ -32,16 +34,17 @@ skill's job.
32
34
  This endpoint is full-replace — GET the EC first and mutate, don't send a partial body.
33
35
  2. Set the principal's client ID + secret (both required together in one call; there is no
34
36
  partial-update path for just the client ID):
35
- **Secret substitution — read this first.** `mcp__headless-360__dispatch` is a JSON API call, **not
36
- a shell**: it does **not** expand `$TEAMS_ENTRA_CLIENT_SECRET`. Passing the literal string
37
- `"$TEAMS_ENTRA_CLIENT_SECRET"` in the body stores that literal text as the OAuth client secret and
38
- Graph authentication then fails after an apparently-successful configuration. You must resolve the
39
- env var to its **actual value** and place that value into `clientSecret.value` at call time. Read it
40
- with a **non-logging** read (e.g. a single `printenv TEAMS_ENTRA_CLIENT_SECRET` captured into an
41
- in-memory variable, or read the secret file) — never `echo`/print it, never place the resolved
42
- secret in any text you emit to the user or into a log, and never write it to disk. The `<secret
43
- value read from $TEAMS_ENTRA_CLIENT_SECRET>` placeholder below denotes that resolved value, not a
44
- literal to send:
37
+ **Secret substitution — read this first.** The credential API body is JSON, **not a shell**: it
38
+ does **not** expand any `$TEAMS_ENTRA_CLIENT_SECRET`-style token. Passing such a literal string in
39
+ the body stores that literal text as the OAuth client secret and Graph authentication then fails
40
+ after an apparently-successful configuration. You must read the secret's **actual value from the
41
+ gitignored secret file** (Step 4a) and place that value into `clientSecret.value` at call time. Do
42
+ it with a **non-logging** read — `cat <secret-file>` captured into an in-memory variable, or build
43
+ the JSON body with a small script that reads the file (as done for the `MSTeamsSetupClientCredentialsEC`
44
+ POST) — never `echo`/print it, never place the resolved secret in any text you emit to the user or
45
+ into a log, and delete any temp body file that held it immediately after the call. The `<secret
46
+ value read from the secret file>` placeholder below denotes that resolved value, not a literal to
47
+ send:
45
48
  ```text
46
49
  mcp__headless-360__dispatch(
47
50
  method: "POST", // or PUT (update-credential) if credentials already exist for this principal
@@ -52,10 +55,10 @@ skill's job.
52
55
  "principalType": "NamedPrincipal",
53
56
  "authenticationProtocol": "OAuth",
54
57
  "authenticationProtocolVariant": "ClientCredentialsClientSecretBasic",
55
- // clientSecret.value MUST be the resolved secret read from the TEAMS_ENTRA_CLIENT_SECRET env
56
- // var / secret file — NOT the literal "$TEAMS_ENTRA_CLIENT_SECRET" token (dispatch does not
57
- // expand shell variables). Resolve in memory via a non-logging read; never echo it.
58
- "credentials": { "clientId": {"value": "<client id>"}, "clientSecret": {"value": "<secret value read from $TEAMS_ENTRA_CLIENT_SECRET>"} }
58
+ // clientSecret.value MUST be the actual secret read from the gitignored secret file (Step 4a)
59
+ // — NOT a literal "$TEAMS_ENTRA_CLIENT_SECRET" token (the JSON body does not expand variables).
60
+ // Read it in memory via a non-logging read (cat the file); never echo it.
61
+ "credentials": { "clientId": {"value": "<client id>"}, "clientSecret": {"value": "<secret value read from the secret file>"} }
59
62
  }
60
63
  )
61
64
  ```
@@ -73,7 +76,7 @@ Enabling the Teams feature also provisions a Microsoft-type **Auth Provider** na
73
76
  Consumer Secret, or endpoint URLs). This is the **inbound SSO** side — it authenticates employees
74
77
  logging into the Experience Cloud portal that the Teams IT Service app embeds. It is a *separate
75
78
  artifact* from the outbound-Graph `MSTeamsSetupClientCredentialsEC` Named Credential, but takes the
76
- **same three values** the user supplied (secret from the env var / file, never chat). Populate it automatically in the same pass — a previous run
79
+ **same three values** the user supplied (secret read from the gitignored secret file, never chat). Populate it automatically in the same pass — a previous run
77
80
  of this skill forgot this step, leaving portal SSO login broken even though the Named Credential
78
81
  was configured.
79
82
 
@@ -90,7 +93,7 @@ deploy it (this sets every field, including the secret, with no UI):
90
93
  <AuthProvider xmlns="http://soap.sforce.com/2006/04/metadata">
91
94
  <authorizeUrl>https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize</authorizeUrl>
92
95
  <consumerKey><CLIENT_ID></consumerKey>
93
- <consumerSecret>${TEAMS_ENTRA_CLIENT_SECRET}</consumerSecret>
96
+ <consumerSecret>__SECRET_PLACEHOLDER__</consumerSecret>
94
97
  <defaultScopes>openid profile email offline_access https://graph.microsoft.com/.default</defaultScopes>
95
98
  <friendlyName>microsoft_auth_provider</friendlyName>
96
99
  <includeOrgIdInIdentifier>false</includeOrgIdInIdentifier>
@@ -106,9 +109,20 @@ sf project deploy start --source-dir force-app --target-org <org-alias>
106
109
  ```
107
110
 
108
111
  **Secret handling:** substitute `<TENANT_ID>` / `<CLIENT_ID>` (non-secret) directly, but inject the
109
- `<consumerSecret>` value from `$TEAMS_ENTRA_CLIENT_SECRET` at build time (e.g. `envsubst` into a
110
- gitignored temp copy under a scratch dir, deploy that, then delete it). **Never commit the populated
111
- file** and never echo the secret. The secret comes from the env var / secret file — not from chat.
112
+ `<consumerSecret>` value **read from the gitignored secret file** (Step 4a) at build time into a
113
+ gitignored temp copy under a scratch dir, deploy that, then delete the whole scratch dir. A verified
114
+ non-logging way to do the substitution (the secret only ever lives in a transient shell var and the
115
+ scratch file, never in emitted text):
116
+ ```bash
117
+ # template has __SECRET_PLACEHOLDER__ where <consumerSecret> should be; <TENANT_ID>/<CLIENT_ID> already filled in
118
+ SECRET="$(cat <secret-file>)" perl -pe 's/__SECRET_PLACEHOLDER__/$ENV{SECRET}/' template.xml \
119
+ > force-app/main/default/authproviders/microsoft_auth_provider.authprovider-meta.xml
120
+ sf project deploy start --source-dir force-app --target-org <org-alias>
121
+ rm -f force-app/main/default/authproviders/microsoft_auth_provider.authprovider-meta.xml # shred secret-bearing file
122
+ ```
123
+ **Never commit the populated file** and never echo the secret. The secret comes from the gitignored
124
+ secret file — not from chat, and not from an env var (the interactive `!`-prefix export does not
125
+ reach the agent's shell).
112
126
 
113
127
  Notes:
114
128
  - Use the **tenant-specific** `/…/<TENANT_ID>/oauth2/v2.0/…` endpoints, not `/common/` or
@@ -13,11 +13,10 @@ step as failed or retrying an enablement guess.
13
13
  | Azure redirect URI must be under the **Web** platform, not SPA | The `microsoft_auth_provider` Auth Provider is a **confidential client** (server-side token exchange using the ConsumerSecret). Azure rejects secret-based token requests against a redirect URI registered as **Single-page application (SPA)**. Symptom: login *appears* to start (Salesforce logs `LoginHistory` "Success" and mints `OauthToken` rows) but the callback fails at `.../services/authcallback/microsoft_auth_provider` with **`OAUTH_APPROVAL_ERROR_GENERIC`**. Fix (verified): register the callback URI under the Azure app's **Web** platform, not SPA. When emitting the callback URL to the user, always say **Web**. See the callback-URL note under "Populating the `microsoft_auth_provider` Auth Provider." |
14
14
  | Portal login "you don't have access to the Microsoft account in Salesforce" → Username must equal the MS email/UPN | A custom Apex registration handler **`MsTeamsItsmSSOHandler`** (Core `service-itsm-teams-impl`, bound to `microsoft_auth_provider`) resolves the signed-in Microsoft user by `SELECT Id FROM User WHERE Username = :data.email` — the **Microsoft `email`/UPN claim must exactly equal a Salesforce `User.Username`** (not `User.Email`, not `FederationIdentifier`); `canCreateUser` returns false (no JIT), and 0 or >1 matches both return null → login denied. **One handler serves BOTH the IT Service (Employee) and IT Desk (Fulfiller) apps.** Fix (verified): set the intended portal user's `Username` to the MS UPN (after confirming no duplicate) via `PATCH .../sobjects/User/<id>` `{"Username":"<ms-upn>"}`. See "Making a portal user resolvable..." under Step 5. |
15
15
  | Portal Connect API `API_DISABLED_FOR_ORG` / 403 → user needs API Enabled | The Teams IT Service (Employee) app calls Connect APIs on the embedded portal (e.g. `/connect/it-service/permissions/EmployeeApp`); without the **API Enabled** user permission these return `API_DISABLED_FOR_ORG` (403 in the Network tab) and the app fails to load data despite a successful login. The managed permission sets (`TeamsForEmployeeUser`, `EmployeeHubEmployeeUser`) don't grant `ApiEnabled` and **can't be edited** (managed-package: MDAPI retrieve "cannot be found", SObject PATCH "invalid record id"). Fix (verified): create + deploy a new **unmanaged** permission set with `ApiEnabled` only and assign it. **Do not add `ChatterInternalUser`** — the Unified Employee license forbids it (assignment fails "user license doesn't allow the permission: ChatterInternalUser"). See "Granting the portal user API Enabled..." under Step 5. |
16
- | Azure/Entra app registration + admin consent have no Salesforce API | Salesforce only exposes a consent URL via an internal Aura controller (no public REST contract) — the user must click through the Azure admin center themselves. Give them the exact steps in Step 4a rather than a vague pointer, and once they provide the Client ID/Tenant ID (in chat) with the Client Secret in the `TEAMS_ENTRA_CLIENT_SECRET` env var / secret file (**never request the secret in chat**), take over immediately and write the credential into Salesforce yourself (see "Populating `MSTeamsSetupClientCredentialsEC`..." under Step 5) — do not tell them to enter it manually in Setup. |
16
+ | Azure/Entra app registration + admin consent have no Salesforce API | Salesforce only exposes a consent URL via an internal Aura controller (no public REST contract) — the user must click through the Azure admin center themselves. Give them the exact steps in Step 4a rather than a vague pointer, and once they provide the Client ID/Tenant ID (in chat) with the Client Secret written to a gitignored secret file via the Step 4a copy-paste command (**never request the secret in chat**; the `!`-prefix `export` route does not reach the agent's shell), take over immediately and write the credential into Salesforce yourself (see "Populating `MSTeamsSetupClientCredentialsEC`..." under Step 5) — do not tell them to enter it manually in Setup. |
17
17
  | Go page's real checklist order (verified from a live screenshot) | The "Integrate Salesforce with Teams" group on the feature's Go page has exactly 3 items, in this order: **Create Microsoft Entra ID App** → **Configure Setup Named Credentials** → **Grant Azure Administrator Consent**. This is a *separate* checklist group from "Set Up Salesforce IT Desk" / "Set Up Salesforce IT Service" (delegated to `service-itsm-teams-itdesk-configure` / `service-itsm-teams-itservice-configure`) — do not conflate the groups when reporting progress to the user. |
18
18
  | "Grant Azure Administrator Consent" consent link is static, not per-org | Clicking "Grant Consent" on the Go page opens a modal with this exact link: `https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=cd6bd63f-41ef-47cc-9465-86e986179a29&response_type=code&redirect_uri=https://salesforce.com&response_mode=query&scope=Organization.ReadWrite.All`. The `client_id` here is Salesforce's own multi-tenant Entra app (**not** the app the user registers in step 1, and **not** related to the Client ID/Secret that go into the Named Credential) — it requests `Organization.ReadWrite.All` from whichever Microsoft tenant the signed-in admin belongs to (`organizations` tenant segment, not a specific tenant ID). headless-360 has no operation that generates this link or reads the Go page's live checklist state (searched `discover` for "grant Azure administrator consent generate consent URL" and "guided setup checklist progress Salesforce Go" — no matching SOR) — paste the link above verbatim and tell the user to click it themselves, signed in as a Microsoft tenant admin. |
19
19
  | `preferredSite` / Teams extension registration **is** a public Connect API (verified) — corrects an earlier assumption | `POST /services/data/v67.0/connect/service-itsm-teams/graph-api/extensions` body `{"siteUrlPathPrefixes": ["<site urlPathPrefix>"]}` registers the Experience Cloud site as the Teams extension target; `PATCH .../extensions/{extensionId}` updates it. Verified live: it dispatches and reaches real logic (not a stub) — it fails with `400 UNKNOWN_EXCEPTION "We couldn't access the credential(s)... external credential \"MSTeamsSetupClientCredentialsEC\" might not exist"` until the Azure/Entra app registration is done and that named/external credential is wired up in Setup. Once the credential exists, call this to complete preferred-site selection — do not treat it as Aura-only. |
20
20
  | `service-itsm-teams-connect-api` SOR (headless-360 `discover`) | Also exposes `get-teams-get-teams-list`, `get-teams-get-channel-list`, `post-teams-channel-message-send`, `get-teams-get-permissions`, `get-service-itsm-teams-collaboration-app-settings` (valid `targetApplication` values are `TeamsFulfillerApp` / `TeamsEmployeeApp`, not `teams`) — useful for verifying end-to-end Teams connectivity after the manual tail is complete. |
21
- | `ms-teams-app-connect-api` (`/connect/ms-teams-app/tenant-config`) gates Step 5 and has **no known unlock path** | `GET`/`PUT`/`DELETE` all return `403 FUNCTIONALITY_NOT_ENABLED [MsTeamsAppApiFamily]`, even after `service-cloud-itsm-teams-integration` is enabled and `MSTeamsSetupClientCredentialsEC` is fully configured. **Verified this is the same blocker as Step 5's "Unable to fetch tenant ID" error** — `post-teams-extension`/`patch-teams-extension-update` internally depend on this tenant-config lookup. Checked and ruled out: (a) no Go feature-enablement API name unlocks it — tried `ms-teams-app`, `ms-teams-app-integration`, `microsoft-teams-app-integration`, `teams-app-connect-api`, `msteams-app-api`, `service-cloud-ms-teams-app-api`, `MsTeamsAppApiFamily` itself, all `400 NOT_FOUND "Could not find the requested feature"`; (b) no `PermissionSetLicense` among all 112 in the org grants it — only `TeamsForEmployeePsl`/`TeamsForITSrvcsPsl` relate to Teams, and neither gates this family. This appears to be a hard org/edition-level license gate with no self-service unlock via headless-360 — if a user hits this, Step 5 cannot be completed in this org; do not keep retrying enablement guesses. |
22
21
  | A `MSTeamsSetupAutomationAccess` ("Automate Microsoft Teams Setup") permission set also auto-provisions | Was unassigned in this session — assign it to the Setup admin driving this flow if further automation steps need it. (The IT Desk/IT Service checklist permission sets — `TeamsForITSrvcsUser`, `TeamsForEmployeeUser`, `MicrosoftGraphAccess` — are documented in the child skills.) |
23
22
  | Version prefix required | headless-360 `dispatch`/`dispatch_readonly` do not resolve API versions — always pass the full `/services/data/vXX.0/...` prefix. |
@@ -11,10 +11,6 @@ metadata:
11
11
  - "service-itsm-teams-employee-agent-configure"
12
12
  - "service-itsm-teams-itdesk-configure"
13
13
  - "service-itsm-teams-itservice-configure"
14
- # No accessCheck gate: this orchestrator's Stage 1 is what enables ITSMTeamsEnabled,
15
- # so it must be invokable on a brand-new org before that preference exists. Downstream
16
- # child skills retain their own accessCheck. Empty array = applies to any org.
17
- accessCheck: []
18
14
  allowed-tools: Read AskUserQuestion
19
15
  ---
20
16
 
@@ -43,9 +39,11 @@ There are exactly **three mandatory halts** and **one branch** in the whole flow
43
39
  - **HALT 1 — Azure/Entra app** (Stage 2): you give the user the app-registration instructions and
44
40
  **wait** for them to register the app and provide the credentials. No Salesforce API can do this.
45
41
  The **Client ID** and **Tenant ID** are non-secret identifiers and may be given in chat; the
46
- **Client Secret is a confidential credential — NEVER ask for it in the conversation.** The user
47
- places it in the `TEAMS_ENTRA_CLIENT_SECRET` environment variable (or a gitignored secret file the
48
- agent is told the path to); the agent reads it from there and never prints, echoes, or logs it.
42
+ **Client Secret is a confidential credential — NEVER ask for it in the conversation.** The agent
43
+ gives the user one exact copy-paste command that writes the secret to a gitignored secret file
44
+ (`! umask 077; printf '%s' 'PASTE-SECRET' > <secret-file> && echo written`) and reads it from that
45
+ file. Keep the leading `!` — it runs the line in this session's Bash so the file persists. The agent
46
+ never prints, echoes, or logs the value.
49
47
  - **HALT 2 — IT Desk app install** (Stage 3): you give the Microsoft Marketplace link and **wait**
50
48
  for the user to reply **"installed"**. No API installs a Teams app into a tenant catalog.
51
49
  - **HALT 3 — IT Service app install** (Stage 4): same as HALT 2, for the IT Service app.
@@ -70,16 +68,17 @@ then continue straight into Stage 2 — do **not** stop here.
70
68
 
71
69
  ### Stage 2 — Microsoft Entra app + Named Credentials ⟶ HALT 1
72
70
  Still within **`service-itsm-teams-configure`** (its Step 4a): give the user the exact Azure/Entra
73
- app-registration clicks **including the Microsoft Graph Application permissions** it lists, and
71
+ app-registration clicks **including the Microsoft Graph permissions** it lists, and
74
72
  **HALT** until they provide the credentials. The **Client ID** and **Tenant ID** are non-secret
75
73
  identifiers — accept them in chat. The **Client Secret is confidential: never request it in the
76
- conversation.** Instruct the user to set it in the `TEAMS_ENTRA_CLIENT_SECRET` environment variable
77
- (or a gitignored secret file, and tell you the path); read it from there. Never print or echo it.
78
- The moment the identifiers are given and the secret is in the env/file:
74
+ conversation.** Give the user one exact copy-paste command that writes it to a gitignored secret file
75
+ (`! umask 077; printf '%s' 'PASTE-SECRET' > <secret-file> && echo written`) and read it from that
76
+ file. Keep the leading `!` — it runs the line in this session's Bash so the file persists. Never
77
+ print or echo it. The moment the identifiers are given and the secret is in the file:
79
78
  - Write those values into the `MSTeamsSetupClientCredentialsEC` Named Credential **and** the
80
79
  `microsoft_auth_provider` Auth Provider **yourself, via API — nothing manual** (the child skill's
81
- Step 5 and its azure-credential-population reference carry the exact API bodies). Reference the
82
- secret by its env var / file path in the API call — do not inline the raw value into any logged text.
80
+ Step 5 and its azure-credential-population reference carry the exact API bodies). Read the
81
+ secret from the file at call time — do not inline the raw value into any logged text.
83
82
  - Give the user the static **Grant Admin Consent** link and register the preferred site (child Step 5).
84
83
  Then continue to Stage 3 automatically.
85
84
 
@@ -87,8 +86,8 @@ Then continue to Stage 3 automatically.
87
86
  Invoke **`service-itsm-teams-itdesk-configure`**. Drive its whole checklist:
88
87
  - Turn on the `OrgHasITSMFulfillerTeams` org preference (via API).
89
88
  - **Manage User Access** — assign the fulfiller permission sets to the confirmed user(s):
90
- `TeamsForITSrvcsUser` + `MicrosoftGraphAccess`, **plus `Teams_Employee_ApiAccess`** (the ECA-
91
- pre-authorized set that also grants **API Enabled** — required for login, not optional).
89
+ `TeamsForITSrvcsUser` + `MicrosoftGraphAccess`, **plus the API Enabled login permission set**
90
+ (commonly `Teams_Employee_ApiAccess`) — required for login, not optional.
92
91
  - **Turn on Swarming** — this stage includes `service-itsm-swarming-configure`
93
92
  (enables `service-cloud-swarming` and sets `SWARM_COLLABORATION_TOOL = "Teams"`).
94
93
  - Give the **IT Desk Microsoft Marketplace link** + help doc, tell the user **the Azure account
@@ -98,9 +97,9 @@ Invoke **`service-itsm-teams-itdesk-configure`**. Drive its whole checklist:
98
97
  ### Stage 4 — Set up IT Service (employee side) ⟶ HALT 3
99
98
  Invoke **`service-itsm-teams-itservice-configure`**. Drive its whole checklist:
100
99
  - Turn on the `OrgHasEmployeeServiceTeams` org preference (via API).
101
- - **Manage User Access** — assign the employee permission sets to the confirmed UEL user(s):
102
- `TeamsForEmployeeUser` + `MicrosoftGraphAccess`, **plus the API Enabled + ECA-authorized access**
103
- the child's login prerequisites require.
100
+ - **Manage User Access** — assign the employee permission set to the confirmed UEL user(s):
101
+ `TeamsForEmployeeUser` (the dialog assigns only this one — **not** `MicrosoftGraphAccess`), **plus
102
+ the API Enabled login permission set** the child's login prerequisites require.
104
103
  - **Select the Digital Experience Site** (`SLACK_PREFERRED_SITE`) via API.
105
104
  - Give the **IT Service Microsoft Marketplace link** + help doc, repeat the **email-must-match** note,
106
105
  and **HALT** until the user replies **"installed."** Then continue to Stage 5.
@@ -133,6 +132,11 @@ portal user. Then tell the user to **retest from a brand-new Teams chat** to con
133
132
  the Entra app is unregistered, or a halt awaiting "installed"), keep that stage **`Blocked`/waiting**
134
133
  and hold at the halt — do not mark it done and do not skip ahead.
135
134
  - Do not re-present a menu. State what just finished and what you're doing next, then do it.
135
+ - **Keep the report tight — summarize, don't transcribe.** Report each stage as a one-line status in
136
+ the stage-progress table plus at most a short sentence of context; do **not** paste the child skill's
137
+ API request/response bodies, tool-call logs, or step-by-step internals into the report — that detail
138
+ lives in the child skill, and re-narrating it here is the single biggest source of a bloated,
139
+ low-signal report. The reader needs *what happened and what's next*, not a replay of every call.
136
140
 
137
141
  ## Completion summary
138
142
 
@@ -26,10 +26,12 @@ Microsoft Teams for ITSM Setup (via service-itsm-teams-coordinate)
26
26
  │ 8 │ Build IT Service embedded agent (optional) │ Not started │
27
27
  └───┴────────────────────────────────────────────┴──────────────────────┘
28
28
 
29
- Next: send me the Azure app's Client ID and Tenant ID, and put the Client Secret in the
30
- TEAMS_ENTRA_CLIENT_SECRET environment variable (or a secret file — tell me the path). Don't paste
31
- the secret here. I'll read it from there and write everything into the Named Credential and Auth
32
- Provider automatically.
29
+ Next: send me the Azure app's Client ID and Tenant ID here. For the Client Secret, DON'T paste it in
30
+ chat — instead copy-paste this one command into the prompt (put your secret's Value between the
31
+ single quotes), then tell me it's done:
32
+ ! umask 077; printf '%s' 'PASTE-CLIENT-SECRET-HERE' > <secret-file> && echo written
33
+ I'll read it from that file and write everything into the Named Credential and Auth Provider
34
+ automatically.
33
35
  ```
34
36
 
35
37
  Status values: `Not started`, `In progress`, `Waiting (<what for>)`, `Blocked`, `Done`.
@@ -37,11 +39,12 @@ Status values: `Not started`, `In progress`, `Waiting (<what for>)`, `Blocked`,
37
39
  ## Halt messages
38
40
 
39
41
  - **HALT 1 (Stage 2 — Azure/Entra app):** deliver the child's app-registration instructions
40
- (including the Microsoft Graph Application permissions) and end with: *"Send me the **Client ID**
41
- and **Tenant ID** here, and put the **Client Secret** in the `TEAMS_ENTRA_CLIENT_SECRET`
42
- environment variable (or a secret file — tell me the path). Please don't paste the secret in chat.
43
- I'll read it from there and populate the Named Credential and Auth Provider automatically — no
44
- manual Setup entry needed."* Then wait.
42
+ (including the Microsoft Graph permissions) and end with: *"Send me the **Client ID**
43
+ and **Tenant ID** here. For the **Client Secret**, please don't paste it in chat — copy-paste this
44
+ one command into the prompt with your secret's Value between the single quotes, then tell me it's
45
+ done: `! umask 077; printf '%s' 'PASTE-CLIENT-SECRET-HERE' > <secret-file> && echo written`. I'll
46
+ read it from that file and populate the Named Credential and Auth Provider automatically — no
47
+ manual Setup entry needed."* (Substitute the real job/temp path for `<secret-file>`.) Then wait.
45
48
  - **HALT 2 / HALT 3 (Stages 3 & 4 — app install):** deliver the Microsoft Marketplace link + help
46
49
  doc, then: *"Install the app in your Microsoft Teams admin center, then reply **installed** and
47
50
  I'll continue. Note: the Azure/Microsoft email the user signs in with must match that Salesforce
@@ -36,8 +36,9 @@ dispatches through **headless-360**.
36
36
 
37
37
  - **In scope**: Turning on the `OrgHasITSMFulfillerTeams` preference; giving the user the exact
38
38
  Teams marketplace link + help doc for the IT Desk app install; assigning
39
- `TeamsForITSrvcsUser`/`MicrosoftGraphAccess` permission sets to confirmed users; delegating
40
- "Set Teams as Collaboration Tool for Swarming" to `service-itsm-swarming-configure`.
39
+ `TeamsForITSrvcsUser`/`MicrosoftGraphAccess` permission sets to confirmed users **plus
40
+ provisioning the org-wide API-Enabled login permission set** (created once, required to sign in);
41
+ delegating "Set Teams as Collaboration Tool for Swarming" to `service-itsm-swarming-configure`.
41
42
  - **Out of scope**: The base Teams Salesforce Go page toggle (`ITSMTeamsEnabled`), Azure/Entra app
42
43
  registration, Named Credential population, and Teams extension/preferred-site registration —
43
44
  use `service-itsm-teams-configure` (a prerequisite for this skill). The IT Service/employee
@@ -103,6 +104,17 @@ live from the "Manage Microsoft Teams for Employee Service User Access" dialog:
103
104
  - `MicrosoftGraphAccess` (label **"MicrosoftGraphAccess"**) — assigned alongside it in the same
104
105
  dialog.
105
106
 
107
+ **A third, "login" permission set is also required — one you provision once per org.** The two
108
+ dialog permsets provision the IT Desk *surface* but **do not let the fulfiller sign in**: both read
109
+ `PermissionsApiEnabled = false`, so the embedded app's Connect calls 403 and login fails with
110
+ "server not reachable." The fulfiller needs a permission set carrying the **API Enabled** system
111
+ permission. Some orgs already have one named `Teams_Employee_ApiAccess` (a **custom** permset — do
112
+ **not** assume a fresh customer org has it); otherwise create it. It is a **shared, org-wide
113
+ artifact** — the same permset also covers IT Service login, so **create it only once** and just
114
+ *assign* it wherever needed. The resolve-or-create-then-assign recipe is in
115
+ [Login prerequisite](#login-prerequisite--provision-the-login-permission-set-verified) below. Do
116
+ this as part of this step; don't wait for login to break.
117
+
106
118
  **Do not just assign every active user.** Ask the user which specific user(s) should get access.
107
119
  If they want to see the list of users first (rather than naming them), page it — **show at most
108
120
  10 users per page**, then ask "want to see more?" before showing the next page, since orgs can
@@ -125,8 +137,9 @@ still want one assigned — but call out which rows look like system accounts so
125
137
  have to guess). If the user says a listed batch is "not employee users, skip," move on to the
126
138
  next page rather than assigning any of them.
127
139
 
128
- Once the user confirms specific user(s), look up each permission set's `Id` (they are stable per
129
- org but don't hardcode them — query fresh):
140
+ Once the user confirms specific user(s), look up the two dialog permission sets' `Id`s (they are
141
+ stable per org but don't hardcode them — query fresh; the third "login" permset is resolved in the
142
+ Login prerequisite below):
130
143
 
131
144
  ```text
132
145
  mcp__headless-360__dispatch_readonly(
@@ -152,46 +165,49 @@ Verify by re-querying `PermissionSetAssignment` for that `AssigneeId`, or simply
152
165
  from the assignment call plus a `SELECT ... FROM PermissionSetAssignment WHERE AssigneeId =
153
166
  '<user id>' AND PermissionSetId = '<permset id>'` readback.
154
167
 
155
- #### Login prerequisite — the two Manage-User-Access permsets are NOT enough to sign in (verified)
156
-
157
- Assigning `TeamsForITSrvcsUser` + `MicrosoftGraphAccess` provisions the IT Desk *surface*, but a
158
- fulfiller who opens the IT Desk app in Teams can still hit **"server not reachable"** on the login
159
- page. The verified root cause is the **`ServiceCloudMSTeamsEca` External Client App OAuth
160
- authorize being denied** — `LoginHistory` for the user shows
161
- `Application = ServiceCloudMSTeamsEca`, `Status = Failed: Not approved for access`
162
- (`LoginType = Remote Access 2.0`). Neither `TeamsForITSrvcsUser` nor `MicrosoftGraphAccess` clears
163
- this, because:
164
-
165
- 1. **They are not pre-authorized to the ECA.** The ECA's policy is `AdminApprovedPreAuthorized`
166
- (verified: `SELECT PermittedUsersPolicyType FROM ExtlClntAppOauthPlcyCnfg WHERE
167
- ExternalClientApplicationId = '<ecaId>'` — Tooling), so **only** users holding a permission set
168
- explicitly pre-authorized on the ECA can complete OAuth. Check which permset that is:
169
- `SELECT ParentId, Parent.Name FROM SetupEntityAccess WHERE SetupEntityId = '<ecaId>'` — in the
170
- verified org the sole authorized set was **`Teams_Employee_ApiAccess`**, and the IT Desk agent did
171
- not hold it.
172
- 2. **They do not grant API Enabled.** Both read `PermissionsApiEnabled = false`; the embedded app's
173
- Connect calls need the **API Enabled** system permission or they 403.
174
-
175
- **Fix (verified to resolve the login):** also assign the fulfiller the **`Teams_Employee_ApiAccess`**
176
- permission set — it is simultaneously the ECA-pre-authorized set **and** carries
177
- `PermissionsApiEnabled = true`, so it clears both blockers in one assignment:
178
-
179
- ```text
180
- mcp__headless-360__dispatch(
181
- method: "POST",
182
- url: "/services/data/v67.0/sobjects/PermissionSetAssignment",
183
- body: { "AssigneeId": "<user id>", "PermissionSetId": "<Teams_Employee_ApiAccess Id>" }
184
- )
185
- ```
186
-
187
- After assigning, have the user **fully close and reopen the Teams app** (the ECA authorize is cached
188
- client-side). Also confirm **CORS Allowed Origins** contains both `https://teams.cloud.microsoft`
189
- and `https://cdn.scs.static.lightning.force.com` (`SELECT UrlPattern FROM CorsWhitelistEntry`). If
190
- login still fails in a fresh session after the ECA-authorized permset is assigned, the remaining
168
+ #### Login prerequisite — provision the login permission set (verified)
169
+
170
+ With only `TeamsForITSrvcsUser` + `MicrosoftGraphAccess` the IT Desk *surface* is provisioned, but a
171
+ fulfiller who opens the IT Desk app in Teams hits **"server not reachable"** on the login page. The
172
+ verified blocker is **API Enabled**: both dialog permsets read `PermissionsApiEnabled = false`
173
+ (verified live), so the embedded app's Connect calls 403. Assigning the fulfiller a permission set
174
+ with `PermissionsApiEnabled = true` resolves the login. That permset is **org-wide, created once**
175
+ and shared with IT Service — resolve-or-create, then assign:
176
+
177
+ 1. **Reuse if it already exists** (an API-Enabled permset — commonly `Teams_Employee_ApiAccess`):
178
+ `SELECT Id, Name, PermissionsApiEnabled FROM PermissionSet WHERE Name = 'Teams_Employee_ApiAccess'`.
179
+ If found with `PermissionsApiEnabled = true`, take its `Id` and skip to step 3.
180
+ 2. **Otherwise create it once** (`PermissionsApiEnabled` is createable — verified):
181
+ ```text
182
+ mcp__headless-360__dispatch(
183
+ method: "POST",
184
+ url: "/services/data/v67.0/sobjects/PermissionSet",
185
+ body: { "Name": "Teams_Employee_ApiAccess", "Label": "Teams Employee API Access", "PermissionsApiEnabled": true }
186
+ )
187
+ ```
188
+ Capture the returned `Id`. Because it's shared org-wide, don't recreate it if a later run (or the
189
+ IT Service skill) already made it — step 1's query is the guard.
190
+ 3. **Assign it** to each confirmed fulfiller, alongside the two dialog permsets:
191
+ ```text
192
+ mcp__headless-360__dispatch(
193
+ method: "POST",
194
+ url: "/services/data/v67.0/sobjects/PermissionSetAssignment",
195
+ body: { "AssigneeId": "<user id>", "PermissionSetId": "<login permset Id>" }
196
+ )
197
+ ```
198
+
199
+ After assigning, have the user **fully close and reopen the Teams app** (the OAuth authorize is
200
+ cached client-side). Also confirm **CORS Allowed Origins** contains both `https://teams.cloud.microsoft`
201
+ and `https://cdn.scs.static.lightning.force.com` (`SELECT UrlPattern FROM CorsWhitelistEntry`).
202
+
203
+ The `ServiceCloudMSTeamsEca` External Client App that backs Teams login is **auto-installed by the
204
+ Go-page toggle and needs no configuration** — `Teams_Employee_ApiAccess` grants API Enabled and is
205
+ unrelated to the ECA. Do not add `SetupEntityAccess` rows or change the ECA's OAuth policy.
206
+
207
+ If login still fails in a fresh session after the API-Enabled permset is assigned, the remaining
191
208
  suspect is the **"Allow OAuth for employees"** profile checkbox (Setup-UI-only — no API write path).
192
- See `service-itsm-teams-itservice-configure`'s *Login prerequisites* and its Troubleshooting
193
- section D (ECA self-authorization) for the full pass/fail diagnostic chain — the same ECA gates both
194
- the fulfiller (IT Desk) and employee (IT Service) apps.
209
+ See `service-itsm-teams-itservice-configure`'s *Login prerequisites* for the full pass/fail
210
+ diagnostic chain.
195
211
 
196
212
  ### Step 4 — Set Teams as Collaboration Tool for Swarming (delegate)
197
213
 
@@ -217,7 +233,7 @@ is now fully automated end-to-end, no manual "Go to Feature Page" click required
217
233
  | `OrgHasITSMFulfillerTeams` does not unblock `ITSMTeamsEnabled` | These are separate bits — enabling this preference does not itself unblock the Teams Salesforce Go page toggle preference, and vice versa. |
218
234
  | "Set Teams as Collaboration Tool for Swarming" needs `service-cloud-swarming` enabled first | Delegate to `service-itsm-swarming-configure` rather than enabling that feature inline. That skill both enables the feature and writes `SWARM_COLLABORATION_TOOL` to `"Teams"` — the whole checklist item is API-reachable, not just the base feature enable. |
219
235
  | Permission sets / PSLs | `TeamsForITSrvcsUser`, `MicrosoftGraphAccess` (permission sets) and PSL `TeamsForITSrvcsPsl` auto-provisioned and were confirmed `Active` (10 licenses) immediately after the feature-enable in this session — no manual PSL/permset creation needed once `TeamsITSrvcsAddOn`+`IncidentManagementAddOn` are licensed. |
220
- | Manage-User-Access permsets don't cover login — assign `Teams_Employee_ApiAccess` too | Verified: after assigning `TeamsForITSrvcsUser` + `MicrosoftGraphAccess`, the IT Desk agent still failed Teams login with **"server not reachable"**; `LoginHistory` showed `ServiceCloudMSTeamsEca` = **"Failed: Not approved for access."** The `ServiceCloudMSTeamsEca` ECA is `AdminApprovedPreAuthorized` and its only pre-authorized permset was `Teams_Employee_ApiAccess`; neither Manage-User-Access set is authorized on the ECA, and both have `PermissionsApiEnabled = false`. Assigning `Teams_Employee_ApiAccess` (ECA-pre-authorized **and** grants API Enabled) resolved the login. See [Step 3 → Login prerequisite](#login-prerequisite--the-two-manage-user-access-permsets-are-not-enough-to-sign-in-verified). |
236
+ | Manage-User-Access permsets don't cover login — assign an API-Enabled permset | Verified: after assigning `TeamsForITSrvcsUser` + `MicrosoftGraphAccess`, the IT Desk agent still failed Teams login with **"server not reachable"** — both dialog permsets have `PermissionsApiEnabled = false`, so the embedded app's Connect calls 403. The fix is an **API-Enabled** permission set (`PermissionsApiEnabled = true`), commonly `Teams_Employee_ApiAccess` — a **custom, org-wide** permset shared with IT Service, so **create it once** then assign. A test org may already have it; **a fresh customer org won't**, so resolve-or-create. (The `ServiceCloudMSTeamsEca` ECA is auto-installed by the Go-page toggle and needs no configuration — it does not gate login and `Teams_Employee_ApiAccess` is unrelated to it.) See [Step 3 → Login prerequisite](#login-prerequisite--provision-the-login-permission-set-verified). |
221
237
  | Version prefix required | headless-360 `dispatch`/`dispatch_readonly` do not resolve API versions — always pass the full `/services/data/vXX.0/...` prefix. |
222
238
 
223
239
  ---