@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.
- package/package.json +1 -1
- package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +72 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/references/inputs-and-namespace.md +38 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/references/procedure.md +158 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/detect-namespace.js +86 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/render-apex.js +64 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/resolve-id-by-name.js +47 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/sf-rest.js +171 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/soql-escape.js +26 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/upsert-report-config.apex +51 -0
- package/skills/consumer-goods-rtr-datacloud-export-configure/scripts/upsert-system-setting.apex +21 -0
- package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +74 -0
- package/skills/consumer-goods-tpe-dashboard-configure/references/phases-1-6.md +112 -0
- package/skills/consumer-goods-tpe-dashboard-configure/references/phases-7-12.md +157 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/find-failure-reason.js +132 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/poll-status.js +116 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/render-apex.js +64 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/run-data-transform.js +121 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/schedule-business-period-export.apex +27 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/sf-rest.js +171 -0
- package/skills/consumer-goods-tpe-dashboard-configure/scripts/soql-escape.js +25 -0
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +141 -0
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/references/payload-shapes.md +447 -0
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/references/procedure.md +263 -0
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/scripts/clone-tpe-dashboards.js +537 -0
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/scripts/sf-rest.js +195 -0
- package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +157 -0
- package/skills/consumer-goods-tpe-datakit-deploy/scripts/detect-namespace.js +86 -0
- package/skills/consumer-goods-tpe-datakit-deploy/scripts/download-static-resource.js +151 -0
- package/skills/consumer-goods-tpe-datakit-deploy/scripts/extract-crm-field-permissions.js +115 -0
- package/skills/consumer-goods-tpe-datakit-deploy/scripts/sf-rest.js +109 -0
- package/skills/consumer-goods-tpe-datakit-deploy/scripts/update-field-permissions.js +433 -0
- package/skills/service-catalog-template-coordinate/SKILL.md +263 -0
- package/skills/service-catalog-template-coordinate/examples/output-templates.md +44 -0
- package/skills/service-catalog-template-coordinate/references/mcp-invocation.md +183 -0
- package/skills/service-catalog-template-coordinate/references/operations.md +230 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/SKILL.md +243 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/cli-invocation.md +205 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/helper-contracts.md +236 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/permset-topology.md +132 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-activated-agents.mjs +106 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-agent-access-state.mjs +113 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-assignment-state.mjs +99 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/classify-platform-permset-availability.mjs +155 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/gate-unified-catalog-tiers.mjs +100 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/rank-candidate-users.mjs +95 -0
- package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/scripts/resolve-target-user.mjs +86 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +44 -23
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +33 -9
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +17 -18
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +3 -1
- package/skills/service-itsm-agentic-setup-configure/SKILL.md +20 -12
- package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +73 -5
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -7
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +45 -33
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +8 -6
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +10 -10
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +114 -56
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +33 -17
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +9 -3
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +43 -32
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +6 -4
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +10 -10
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +106 -55
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +27 -13
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +9 -3
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +159 -161
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +51 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +1 -1
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +120 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +28 -5
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +19 -1
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +350 -30
- package/skills/service-itsm-channels-coordinate/SKILL.md +80 -213
- package/skills/service-itsm-slack-itservice-configure/SKILL.md +363 -0
- package/skills/service-itsm-slack-itservice-configure/references/connect-agentforce-to-slack.md +159 -0
- package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +88 -0
- package/skills/service-itsm-slack-itservice-configure/references/manage-user-access.md +117 -0
- package/skills/service-itsm-slack-itservice-configure/references/record-visibility.md +78 -0
- package/skills/service-itsm-slack-itservice-configure/references/site-membership-verification.md +126 -0
- package/skills/service-itsm-slack-itservice-configure/scripts/classify-user-access.mjs +167 -0
- package/skills/service-itsm-teams-configure/SKILL.md +50 -47
- package/skills/service-itsm-teams-configure/references/azure-credential-population.md +42 -28
- package/skills/service-itsm-teams-configure/references/gotchas.md +1 -2
- package/skills/service-itsm-teams-coordinate/SKILL.md +22 -18
- package/skills/service-itsm-teams-coordinate/examples/output-templates.md +12 -9
- package/skills/service-itsm-teams-itdesk-configure/SKILL.md +60 -44
- package/skills/service-itsm-teams-itservice-configure/SKILL.md +56 -70
- package/skills/service-catalog-template-deploy/SKILL.md +0 -310
- package/skills/service-catalog-template-deploy/references/cli-invocation.md +0 -258
- package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +0 -164
- package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +0 -94
- package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +0 -331
- package/skills/service-catalog-template-search/SKILL.md +0 -212
- package/skills/service-catalog-template-search/references/cli-invocation.md +0 -128
- package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +0 -205
package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/cli-invocation.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# CLI Invocation — service-itsm-agentic-setup-agent-runtime-access-assign
|
|
2
|
+
|
|
3
|
+
Every read and write uses the **Salesforce CLI (`sf`)** against the CLI's stored
|
|
4
|
+
session for `--target-org <alias>`. **Never extract the access token** from
|
|
5
|
+
`sf org display` — hand-building a raw HTTP request bypasses the CLI session and
|
|
6
|
+
leaks a bearer token into shell context.
|
|
7
|
+
|
|
8
|
+
## `--json` rule
|
|
9
|
+
|
|
10
|
+
- `sf data query` **takes** `--json` → `{status, result:{records:[...]}}` envelope. That is what the classifier scripts expect.
|
|
11
|
+
- `sf api request rest` does **not** — its raw stdout body is already JSON. Passing `--json` errors on some endpoints.
|
|
12
|
+
- `sf org assign permset` **takes** `--json` → `result:{successes:[...], failures:[...]}`.
|
|
13
|
+
|
|
14
|
+
## Phase 1 — discovery reads
|
|
15
|
+
|
|
16
|
+
Platform feature permsets (see `permset-topology.md` for the fixed six Names):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
sf data query \
|
|
20
|
+
-q "SELECT Id, Name, Label, LicenseId FROM PermissionSet WHERE Name IN ('EinsteinGPTPromptTemplateUser','EinsteinGPTPromptTemplateManager','GenieUserEnhancedSecurity','GenieAdmin','UnifiedCatalogCommunityUser','UnifiedCatalogAdmin')" \
|
|
21
|
+
--target-org <alias> --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Activated agents (an agent is activated iff the `BotVersions` child returns ≥1 row):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
sf data query \
|
|
28
|
+
-q "SELECT Id, DeveloperName, MasterLabel, (SELECT Status FROM BotVersions WHERE Status='Active') FROM BotDefinition WHERE Type='InternalCopilot'" \
|
|
29
|
+
--target-org <alias> --json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Phase 2 — identity read
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sf api request rest "/services/data/v67.0/" --method GET --target-org <alias>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`identity` is a URL ending in `/<orgId>/<userId>`; take the trailing `005…`
|
|
39
|
+
segment via `scripts/resolve-target-user.mjs`. Do NOT call `USER_ID()` (Apex-only)
|
|
40
|
+
or `/chatter/users/me` (403 when Chatter is off).
|
|
41
|
+
|
|
42
|
+
The resolver returns only `{ userId, identity, verdict }` — it carries no name. To
|
|
43
|
+
label the running-user option **"Me — <name>"** (fall back to just **"Me"** if this
|
|
44
|
+
returns nothing), read the name explicitly. Then query active org users with the
|
|
45
|
+
fields the ranker needs (`Profile.Name`, `Profile.UserLicense.Name`) and hand them
|
|
46
|
+
to `rank-candidate-users.mjs`, which filters out service/integration/bot/agent
|
|
47
|
+
accounts and returns up to five real candidates ranked for the `<audience>`
|
|
48
|
+
(`fulfiller` ⇒ standard-license users first; `employee` ⇒ Unified Employee users
|
|
49
|
+
first; `any` ⇒ input order):
|
|
50
|
+
|
|
51
|
+
The running-user query also selects `Profile.Name` + `Profile.UserLicense.Name` —
|
|
52
|
+
the Unified Catalog gate (Phase 3) needs the target user's license/profile:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
sf data query -q "SELECT Name, Profile.Name, Profile.UserLicense.Name FROM User WHERE Id = '<userId>'" \
|
|
56
|
+
--target-org <alias> --json > /tmp/itsm-running-user.json 2>/dev/null || true
|
|
57
|
+
|
|
58
|
+
sf data query -q "SELECT Id, Name, Username, Profile.Name, Profile.UserLicense.Name FROM User WHERE IsActive = true ORDER BY LastLoginDate DESC NULLS LAST LIMIT 25" \
|
|
59
|
+
--target-org <alias> --json > /tmp/itsm-candidate-users.json 2>/dev/null || true
|
|
60
|
+
|
|
61
|
+
node "<skill_dir>/scripts/rank-candidate-users.mjs" /tmp/itsm-candidate-users.json <audience> <userId>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `AskUserQuestion` picker takes at most four options, so offer **"Me — <name>"**
|
|
65
|
+
(recommended) plus the **top three** ranked candidates; its built-in **"Other"**
|
|
66
|
+
free-text option covers any username not listed. Determine `<audience>` from the
|
|
67
|
+
agent this grant is for (named in the request/handoff, or the Phase-1 activated
|
|
68
|
+
set) — a Fulfiller agent is run by IT staff (standard license), an Employee agent
|
|
69
|
+
by end employees (Unified Employee).
|
|
70
|
+
|
|
71
|
+
Named user (or any chosen/typed option) — also select the profile + license so the
|
|
72
|
+
Unified Catalog gate can run for this user. **Capture each selected user to its own
|
|
73
|
+
file**, keyed by username — never a single shared path: the target-user picker is a
|
|
74
|
+
multi-select, so a fixed file would clobber earlier users and mis-gate them against
|
|
75
|
+
the last user's license/profile:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Run once per selected user; each writes a distinct, username-keyed file.
|
|
79
|
+
sf data query -q "SELECT Id, Username, Name, IsActive, Profile.Name, Profile.UserLicense.Name FROM User WHERE Username = '<username>'" \
|
|
80
|
+
--target-org <alias> --json > "/tmp/itsm-target-user-<username>.json"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Phase 3 — Unified Catalog per-user tier gate
|
|
84
|
+
|
|
85
|
+
The Unified Catalog PSLs are license-**shape** gated: the Community User tier can
|
|
86
|
+
be held only by a **Unified Employee** user and the Admin tier only by a **System
|
|
87
|
+
Administrator**. Before asking the Unified Catalog tier, run the gate **once per
|
|
88
|
+
selected target user** against **that user's own capture**
|
|
89
|
+
(`/tmp/itsm-running-user.json` for the running user,
|
|
90
|
+
`/tmp/itsm-target-user-<username>.json` for each named user) plus the Phase-1
|
|
91
|
+
availability capture, and **retain each user's `offer[]`/`omit` with that user's
|
|
92
|
+
assignment plan** — never reuse one user's result for another. Offer only the tiers
|
|
93
|
+
in `offer[]`, and on `omit` skip Unified Catalog for that user as "not applicable for
|
|
94
|
+
this user's license/profile — skipped":
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
node "<skill_dir>/scripts/classify-platform-permset-availability.mjs" /tmp/itsm-platform-permsets.json > /tmp/itsm-availability.json
|
|
98
|
+
# Running user:
|
|
99
|
+
node "<skill_dir>/scripts/gate-unified-catalog-tiers.mjs" /tmp/itsm-availability.json /tmp/itsm-running-user.json
|
|
100
|
+
# Each named user — against that user's own capture:
|
|
101
|
+
node "<skill_dir>/scripts/gate-unified-catalog-tiers.mjs" /tmp/itsm-availability.json "/tmp/itsm-target-user-<username>.json"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Phase 4 — idempotency reads
|
|
105
|
+
|
|
106
|
+
Agent Access permset + its existing `BotDefinition` grants (second query only
|
|
107
|
+
when the permset exists — else pass `NO-PERMSET` to the classifier):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
sf data query -q "SELECT Id, Name, Label FROM PermissionSet WHERE Name='Agent_Access'" \
|
|
111
|
+
--target-org <alias> --json > /tmp/agent-access.json
|
|
112
|
+
|
|
113
|
+
sf data query -q "SELECT SetupEntityId FROM SetupEntityAccess WHERE ParentId='<permsetId>' AND SetupEntityType='BotDefinition'" \
|
|
114
|
+
--target-org <alias> --json > /tmp/sea.json
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Per user + permset (feature tier or `Agent_Access`). PSLA query only when the
|
|
118
|
+
selected tier's `needsPsl:true`:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
sf data query -q "SELECT Id FROM PermissionSetAssignment WHERE AssigneeId='<userId>' AND PermissionSetId='<permsetId>'" \
|
|
122
|
+
--target-org <alias> --json > /tmp/psa.json
|
|
123
|
+
|
|
124
|
+
sf data query -q "SELECT Id FROM PermissionSetLicenseAssign WHERE AssigneeId='<userId>' AND PermissionSetLicenseId='<licenseId>'" \
|
|
125
|
+
--target-org <alias> --json > /tmp/psla.json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Phase 6 — writes
|
|
129
|
+
|
|
130
|
+
**Create `Agent_Access`** (only if `needsCreate`). `Name` is the API name;
|
|
131
|
+
`Label` is the display label:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
sf api request rest "/services/data/v67.0/sobjects/PermissionSet" \
|
|
135
|
+
--method POST \
|
|
136
|
+
--body '{"Name":"Agent_Access","Label":"Agent Access"}' \
|
|
137
|
+
--target-org <alias>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Response: `{"id":"0PS...","success":true,"errors":[]}`. Capture `id` — it is the
|
|
141
|
+
`ParentId` for the grants.
|
|
142
|
+
|
|
143
|
+
**Grant each chosen agent** (`SetupEntityId` = the `BotDefinition` Id). Send
|
|
144
|
+
`ParentId` + `SetupEntityId` ONLY — `SetupEntityType` is not creatable:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
sf api request rest "/services/data/v67.0/sobjects/SetupEntityAccess" \
|
|
148
|
+
--method POST \
|
|
149
|
+
--body '{"ParentId":"<permsetId>","SetupEntityId":"<botDefinitionId>"}' \
|
|
150
|
+
--target-org <alias>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`DUPLICATE_VALUE` here ⇒ that agent is already granted; treat as success.
|
|
154
|
+
|
|
155
|
+
**PSL first, then permset** for a license-gated feature tier (`needsPsl:true`).
|
|
156
|
+
Use the selected tier's own `LicenseId` as `PermissionSetLicenseId`:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
sf api request rest "/services/data/v67.0/sobjects/PermissionSetLicenseAssign" \
|
|
160
|
+
--method POST \
|
|
161
|
+
--body '{"AssigneeId":"<userId>","PermissionSetLicenseId":"<licenseId>"}' \
|
|
162
|
+
--target-org <alias>
|
|
163
|
+
|
|
164
|
+
# Running user (the default target): OMIT --on-behalf-of; the command assigns to
|
|
165
|
+
# the authenticated user.
|
|
166
|
+
sf org assign permset --name "<permsetName>" --target-org <alias> --json
|
|
167
|
+
# A NAMED target user: pass their resolved <username> — NOT a 005 Id.
|
|
168
|
+
sf org assign permset --name "<permsetName>" --on-behalf-of "<username>" \
|
|
169
|
+
--target-org <alias> --json
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
> **`--on-behalf-of` resolves by `Username`/alias, not a `005…` user Id.** Passing
|
|
173
|
+
> a user Id fails to match. For the running user (the default target) omit the flag
|
|
174
|
+
> entirely; for a named user pass the `<username>` resolved by the
|
|
175
|
+
> `WHERE Username=` query. Do **not** substitute a `$USERNAME` shell variable — in
|
|
176
|
+
> zsh it is a read-only builtin bound to the OS user and will silently mis-target.
|
|
177
|
+
|
|
178
|
+
**`Agent_Access` assignment** per user (standalone — no PSL):
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Running user (default): OMIT --on-behalf-of.
|
|
182
|
+
sf org assign permset --name "Agent_Access" --target-org <alias> --json
|
|
183
|
+
# Named user: --on-behalf-of "<username>" (Username, never a 005 Id).
|
|
184
|
+
sf org assign permset --name "Agent_Access" --on-behalf-of "<username>" \
|
|
185
|
+
--target-org <alias> --json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`sf org assign permset` response: `result.successes[]` / `result.failures[]`; a
|
|
189
|
+
`failure.message` matching `Duplicate id`/`already has` is idempotent success.
|
|
190
|
+
|
|
191
|
+
## Phase 7 — verify read-backs
|
|
192
|
+
|
|
193
|
+
Re-run the Phase-4 `PermissionSetAssignment` / `PermissionSetLicenseAssign`
|
|
194
|
+
queries for each target user, and the `SetupEntityAccess` query for
|
|
195
|
+
`Agent_Access`, and confirm each intended row is now present.
|
|
196
|
+
|
|
197
|
+
## Common error responses (surface verbatim)
|
|
198
|
+
|
|
199
|
+
| Status / errorCode | Meaning | Handling |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `400 DUPLICATE_VALUE` on any POST | Row already exists | Idempotent success; not a failure |
|
|
202
|
+
| `400 INSUFFICIENT_ACCESS` on a PSL POST | Seat exhausted | STOP that write; tell the user no seats are available |
|
|
203
|
+
| `400`/`404` on `SetupEntityAccess` POST with `SetupEntityType` in body | Field not creatable | Remove `SetupEntityType`; send `ParentId`+`SetupEntityId` only |
|
|
204
|
+
| `401 Unauthorized` | CLI session expired | `sf org login web --alias <alias>` and retry |
|
|
205
|
+
| `404 Not Found` on `sf org assign permset` | Permset name absent on this org | Re-run Phase 1 discovery; org state may have changed |
|
package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/helper-contracts.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Helper Script Contracts — service-itsm-agentic-setup-agent-runtime-access-assign
|
|
2
|
+
|
|
3
|
+
All seven scripts are deterministic, side-effect-free JSON classifiers (A9). Each
|
|
4
|
+
reads one or more `sf data query --json` / `sf api request rest` captures and
|
|
5
|
+
emits a single JSON object to stdout. Exit is `0` on any parseable body — the
|
|
6
|
+
verdict is carried in the payload. Exit `2` is a usage error (missing args); the
|
|
7
|
+
scripts never exit non-zero on a workflow-blocking condition — that is the
|
|
8
|
+
caller's job based on the emitted `verdict`.
|
|
9
|
+
|
|
10
|
+
## `scripts/classify-platform-permset-availability.mjs`
|
|
11
|
+
|
|
12
|
+
Which platform features are provisioned, and each tier's `present` + `needsPsl`.
|
|
13
|
+
|
|
14
|
+
### Input
|
|
15
|
+
|
|
16
|
+
1. `permsets.json` — `sf data query --json` capture of `PermissionSet` filtered
|
|
17
|
+
to the six known feature-tier `Name` values (see `permset-topology.md`).
|
|
18
|
+
|
|
19
|
+
### Output
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"features": [
|
|
24
|
+
{ "feature": "Prompt Templates",
|
|
25
|
+
"tiers": {
|
|
26
|
+
"use": { "tier":"use", "name":"EinsteinGPTPromptTemplateUser", "displayLabel":"Prompt Template User", "present":true, "Id":"0PS…", "LicenseId":"0PL…", "needsPsl":true },
|
|
27
|
+
"admin": { "tier":"admin", "name":"EinsteinGPTPromptTemplateManager", "displayLabel":"Prompt Template Manager", "present":true, "Id":"0PS…", "LicenseId":"0PL…", "needsPsl":true }
|
|
28
|
+
},
|
|
29
|
+
"anyPresent": true }
|
|
30
|
+
],
|
|
31
|
+
"provisionedFeatures": ["Prompt Templates","Data Cloud"],
|
|
32
|
+
"absentFeatures": ["Unified Catalog"],
|
|
33
|
+
"verdict": "ASSIGNABLE",
|
|
34
|
+
"reasons": ["..."]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `displayLabel` prefers the org's own `Label`; falls back to a canonical label only when the row is absent.
|
|
39
|
+
- `needsPsl` is per row (`LicenseId !== null`). Read it from the SELECTED tier.
|
|
40
|
+
|
|
41
|
+
| verdict | Meaning | Caller action |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `ASSIGNABLE` | ≥1 feature provisioned | Ask a tier per provisioned feature; skip + report absent features |
|
|
44
|
+
| `NONE-PROVISIONED` | no feature permset present | Report it; still continue to the Agent Access concern |
|
|
45
|
+
| `CANNOT-CONFIRM` | query envelope unparseable | Surface `reasons[]` verbatim and stop |
|
|
46
|
+
|
|
47
|
+
**Never auto-select a tier.** Present use/agent vs admin and let the user pick.
|
|
48
|
+
|
|
49
|
+
## `scripts/gate-unified-catalog-tiers.mjs`
|
|
50
|
+
|
|
51
|
+
Per **target user**, which **Unified Catalog** tiers are eligible to offer — or
|
|
52
|
+
whether to omit Unified Catalog for that user. The Unified Catalog PSLs are
|
|
53
|
+
license-**shape** gated (not seat-gated): the Community User tier can be held only
|
|
54
|
+
by a **Unified Employee**-licensed user, and the Admin tier is meaningful only for
|
|
55
|
+
a **System Administrator**. Offering a tier the user's license/profile can never
|
|
56
|
+
hold is a hard write-time failure, so this gate runs *before* the tier prompt.
|
|
57
|
+
|
|
58
|
+
### Input (two positional args)
|
|
59
|
+
|
|
60
|
+
1. `availability.json` — the `classify-platform-permset-availability.mjs` output
|
|
61
|
+
capture (carries the Unified Catalog `use`/`admin` tier objects with
|
|
62
|
+
`present`/`Id`/`LicenseId`/`needsPsl`).
|
|
63
|
+
2. `user.json` — a `sf data query --json` capture of the **one** target user,
|
|
64
|
+
selecting `Profile.Name` and `Profile.UserLicense.Name`.
|
|
65
|
+
|
|
66
|
+
### Output
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"feature": "Unified Catalog",
|
|
71
|
+
"provisioned": true,
|
|
72
|
+
"user": { "profile":"System Administrator", "license":"Salesforce", "unifiedEmployee":false, "sysAdmin":true },
|
|
73
|
+
"offer": [ { "tier":"admin", "name":"UnifiedCatalogAdmin", "Id":"0PS…", "LicenseId":"0PL…", "needsPsl":true } ],
|
|
74
|
+
"omit": false,
|
|
75
|
+
"note": "..."
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `offer[]` is the subset of **present** UC tiers this user is eligible for: `use`
|
|
80
|
+
(`UnifiedCatalogCommunityUser`) only when `unifiedEmployee`; `admin`
|
|
81
|
+
(`UnifiedCatalogAdmin`) only when `sysAdmin`. Feed those tier objects straight to
|
|
82
|
+
the tier prompt / write path.
|
|
83
|
+
- `omit:true` (empty `offer[]`) ⇒ do **not** present Unified Catalog for this user;
|
|
84
|
+
report it "not applicable for this user's license/profile — skipped" (never a
|
|
85
|
+
failed write). Run the gate **once per target user**, each against **that user's
|
|
86
|
+
own capture file** (the target-user picker is a multi-select — capture each user to
|
|
87
|
+
a distinct `/tmp/itsm-target-user-<username>.json`, never a shared path that a later
|
|
88
|
+
lookup would clobber), and retain each user's result with that user's assignment
|
|
89
|
+
plan — different users can differ.
|
|
90
|
+
- Fails **closed**: an unreadable availability or user capture ⇒ `omit:true` (better
|
|
91
|
+
to skip than to offer a tier that will fail); the reason is in `note`. Always exits
|
|
92
|
+
`0` on parseable bodies; exit `2` only on missing argv.
|
|
93
|
+
|
|
94
|
+
## `scripts/resolve-target-user.mjs`
|
|
95
|
+
|
|
96
|
+
Extracts the running user's `005…` Id from the API-root `identity` URL.
|
|
97
|
+
|
|
98
|
+
### Input
|
|
99
|
+
|
|
100
|
+
1. `api-root.json` — capture of `sf api request rest "/services/data/v67.0/" --method GET`.
|
|
101
|
+
|
|
102
|
+
### Output
|
|
103
|
+
|
|
104
|
+
`{ userId, identity, verdict: "RESOLVED" | "CANNOT-CONFIRM", reasons }`. The
|
|
105
|
+
trailing path segment must match `^005[A-Za-z0-9]{12}([A-Za-z0-9]{3})?$` (15 or
|
|
106
|
+
18 chars). Any other shape ⇒ `CANNOT-CONFIRM` (surface verbatim; do NOT fall back
|
|
107
|
+
to prose parsing).
|
|
108
|
+
|
|
109
|
+
## `scripts/rank-candidate-users.mjs`
|
|
110
|
+
|
|
111
|
+
Up to five real, non-service candidate users to OFFER as selectable options when
|
|
112
|
+
the caller did not name a target user. A presentation aid, never a gating decision.
|
|
113
|
+
|
|
114
|
+
### Input (three positional args)
|
|
115
|
+
|
|
116
|
+
1. `users.json` — `sf data query --json` capture selecting active users with
|
|
117
|
+
`Id, Name, Username, Profile.Name, Profile.UserLicense.Name`.
|
|
118
|
+
2. `audience` — `fulfiller` | `employee` | `any` (anything else ⇒ `any`). A
|
|
119
|
+
Fulfiller agent is run by IT staff on a **standard** license; an Employee agent
|
|
120
|
+
by end employees on a **Unified Employee** license — the matching cohort is
|
|
121
|
+
surfaced first.
|
|
122
|
+
3. `runningUserId` (optional) — the "Me" user, excluded from candidates (it is
|
|
123
|
+
offered separately as the recommended option).
|
|
124
|
+
|
|
125
|
+
### Output
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"candidates": [ { "Id":"005…", "Name":"Ada Lovelace", "Username":"ada@example.com", "profile":"Standard User", "cohort":"standard" } ],
|
|
130
|
+
"audience": "fulfiller",
|
|
131
|
+
"total": 3,
|
|
132
|
+
"note": "Offering 3 candidate(s), standard cohort first (audience: fulfiller)."
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- Service/integration/bot/agent accounts (matched on profile, license, username,
|
|
137
|
+
or display name) are filtered out; `candidates[]` is capped at five.
|
|
138
|
+
- `cohort` is `unified-employee` when the user's Unified Employee **license**
|
|
139
|
+
(`Profile.UserLicense.Name`) matches — or, defensively, their `Profile.Name` — else
|
|
140
|
+
`standard`. The license is the authoritative signal, so a custom profile carrying
|
|
141
|
+
the license still ranks as Unified Employee. The audience-matching cohort is ranked
|
|
142
|
+
first; input order (the query orders by most-recent login) is preserved within a cohort.
|
|
143
|
+
- Empty `candidates[]` (no non-service humans, or an unreadable capture) ⇒ offer
|
|
144
|
+
**"Me"** plus the free-text **"Other"** option only. Always exits `0` on a
|
|
145
|
+
parseable body; exit `2` only on missing argv.
|
|
146
|
+
- The `AskUserQuestion` picker takes ≤4 options, so offer **"Me"** plus the **top
|
|
147
|
+
three** candidates; the rest stay reachable via **"Other"**.
|
|
148
|
+
|
|
149
|
+
## `scripts/classify-activated-agents.mjs`
|
|
150
|
+
|
|
151
|
+
The activated-agent candidate list for the `Agent_Access` grants.
|
|
152
|
+
|
|
153
|
+
### Input
|
|
154
|
+
|
|
155
|
+
1. `bot-definitions.json` — capture of the `BotDefinition` + `(SELECT Status FROM BotVersions WHERE Status='Active')` query.
|
|
156
|
+
|
|
157
|
+
### Output
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"agents": [ { "Id":"0Xx…", "DeveloperName":"IT_Service_Fulfiller_Agent", "MasterLabel":"IT Service Fulfiller Agent", "active": true } ],
|
|
162
|
+
"activatedAgents": [ { "Id":"0Xx…", "DeveloperName":"…", "MasterLabel":"…" } ],
|
|
163
|
+
"inactiveAgents": [],
|
|
164
|
+
"verdict": "AGENTS-FOUND" | "NONE-ACTIVE" | "CANNOT-CONFIRM",
|
|
165
|
+
"reasons": ["..."]
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
An agent is `active` iff its `BotVersions` child subquery returns ≥1 row. Only
|
|
170
|
+
`activatedAgents[]` are offered for the multi-select.
|
|
171
|
+
|
|
172
|
+
| verdict | Meaning | Caller action |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| `AGENTS-FOUND` | ≥1 activated agent | Present `activatedAgents[]` for multi-select |
|
|
175
|
+
| `NONE-ACTIVE` | no activated agent (none exist, or none active) | Report it; if features are also `NONE-PROVISIONED`, stop |
|
|
176
|
+
| `CANNOT-CONFIRM` | query envelope unparseable | Surface `reasons[]` verbatim and stop |
|
|
177
|
+
|
|
178
|
+
## `scripts/classify-agent-access-state.mjs`
|
|
179
|
+
|
|
180
|
+
Whether `Agent_Access` must be created and which chosen agents still need a grant.
|
|
181
|
+
|
|
182
|
+
### Input (three positional args)
|
|
183
|
+
|
|
184
|
+
1. `agent-access-permset.json` — `PermissionSet WHERE Name='Agent_Access'` capture.
|
|
185
|
+
2. `sea-existing.json` **OR** the sentinel `NO-PERMSET`:
|
|
186
|
+
- permset present ⇒ pass the `SetupEntityAccess WHERE ParentId=<permsetId> AND SetupEntityType='BotDefinition'` capture.
|
|
187
|
+
- permset absent ⇒ pass `NO-PERMSET` (no parent to query yet).
|
|
188
|
+
3. `chosenAgentIds-csv` — comma-separated `BotDefinition` Ids the user selected.
|
|
189
|
+
|
|
190
|
+
### Output
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"permsetExists": false, "permsetId": null,
|
|
195
|
+
"chosenAgentIds": ["0Xx…","0Xx…"],
|
|
196
|
+
"grantedAgentIds": [], "missingAgentIds": ["0Xx…","0Xx…"],
|
|
197
|
+
"needsCreate": true, "needsGrants": true,
|
|
198
|
+
"verdict": "NEEDS-WORK" | "ALREADY-COMPLETE" | "CANNOT-CONFIRM",
|
|
199
|
+
"reasons": ["..."]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
| verdict | Meaning | Caller action |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `NEEDS-WORK` | permset missing and/or ≥1 chosen agent ungranted | Confirm-to-write, then create (if `needsCreate`) + grant each `missingAgentIds` |
|
|
206
|
+
| `ALREADY-COMPLETE` | permset exists and grants every chosen agent | No `SetupEntityAccess` write; still assign the permset to the user(s) if needed |
|
|
207
|
+
| `CANNOT-CONFIRM` | envelope unparseable, or a contradictory `NO-PERMSET`/empty-chosen input | Surface `reasons[]` verbatim and stop |
|
|
208
|
+
|
|
209
|
+
## `scripts/classify-assignment-state.mjs`
|
|
210
|
+
|
|
211
|
+
Per user + permset idempotency (feature tier OR `Agent_Access`).
|
|
212
|
+
|
|
213
|
+
### Input (two positional args)
|
|
214
|
+
|
|
215
|
+
1. `psa-existing.json` — `PermissionSetAssignment` capture for the target user + permset Id.
|
|
216
|
+
2. `psla-existing.json` **OR** the sentinel `NO-PSL`:
|
|
217
|
+
- selected tier `needsPsl:true` ⇒ pass the `PermissionSetLicenseAssign` capture.
|
|
218
|
+
- standalone (`Agent_Access`, or any `needsPsl:false` tier) ⇒ pass `NO-PSL`; `licenseAssigned` is reported `null`.
|
|
219
|
+
|
|
220
|
+
### Output
|
|
221
|
+
|
|
222
|
+
`{ permsetAssigned, licenseAssigned, needsWrite, verdict, reasons }`.
|
|
223
|
+
|
|
224
|
+
| verdict | Meaning | Caller action |
|
|
225
|
+
|---|---|---|
|
|
226
|
+
| `NEEDS-WRITE` | permset (or, when `needsPsl:true`, its license) missing | Confirm-to-write, then assign (PSL first if `needsPsl:true`; permset only if `false`) |
|
|
227
|
+
| `ALREADY-ASSIGNED` | all applicable rows present | Skip the write; go to verify |
|
|
228
|
+
| `CANNOT-CONFIRM` | a query envelope was unparseable | Surface `reasons[]` verbatim and stop |
|
|
229
|
+
|
|
230
|
+
## Why deterministic classifiers?
|
|
231
|
+
|
|
232
|
+
Every decision that gates a write or a success report lives in a script, not in
|
|
233
|
+
prose. Model interpretation of `records[].length === 0` is a documented source of
|
|
234
|
+
false-positive skips ("empty, so nothing exists — proceed") when the real cause
|
|
235
|
+
was an auth failure that returned an empty envelope. The scripts distinguish a
|
|
236
|
+
real empty result from a failed read and carry the difference in the verdict.
|
package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/references/permset-topology.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Platform Feature Permset Topology + Agent Access Mechanism
|
|
2
|
+
|
|
3
|
+
This skill grants a **user** two kinds of access after an ITSM agent is
|
|
4
|
+
activated:
|
|
5
|
+
|
|
6
|
+
1. the **runtime action-execution permissions** the agent's actions call, and
|
|
7
|
+
2. **access to the activated agents themselves** via a custom `Agent_Access`
|
|
8
|
+
permission set.
|
|
9
|
+
|
|
10
|
+
## 1. Platform feature permsets (runtime action execution)
|
|
11
|
+
|
|
12
|
+
Verified live against real orgs. Each feature has a lighter **use/agent** tier
|
|
13
|
+
(enough to *use* the feature at runtime) and a full **admin** tier. All shipped
|
|
14
|
+
tiers observed are **license-gated** (`LicenseId != null` → `needsPsl:true`), but
|
|
15
|
+
the write path never assumes this — it reads `needsPsl` per row.
|
|
16
|
+
|
|
17
|
+
| Feature | use/agent tier (PermissionSet.Name) | admin tier (PermissionSet.Name) | Notes |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| Prompt Templates | `EinsteinGPTPromptTemplateUser` ("Prompt Template User") | `EinsteinGPTPromptTemplateManager` ("Prompt Template Manager") | both tiers share one PSL (`EinsteinGPTPromptTemplatesPsl`) |
|
|
20
|
+
| Data Cloud | `GenieUserEnhancedSecurity` ("Data Cloud User") | `GenieAdmin` (ships as "Data Cloud Architect" or "Data Cloud Admin") | both tiers share one PSL (`GenieDataPlatformStarterPsl`) |
|
|
21
|
+
| Unified Catalog | `UnifiedCatalogCommunityUser` ("Unified Catalog Community User") | `UnifiedCatalogAdmin` ("Unified Catalog Admin") | tiers are backed by per-tier PSLs (`UnifiedCatalogCommunityUserPsl` / `UnifiedCatalogAdminPsl`). **`UnifiedCatalogAgent` is NOT the human tier** — its shipped Description reads "Enables the *agent* to run service process", i.e. it is the agent's own bot-runtime identity permset, not what a human user assigns to exercise the agent |
|
|
22
|
+
|
|
23
|
+
### Key facts
|
|
24
|
+
|
|
25
|
+
- **No single org has all three features.** On a Prompt-Template + Data-Cloud
|
|
26
|
+
org, the two Unified Catalog rows simply do not exist — the classifier reports
|
|
27
|
+
Unified Catalog `absent` and the skill skips it. This is expected, not a
|
|
28
|
+
failure. Detect-if-present / assign-what-is-there / report-the-rest is the
|
|
29
|
+
whole point of the availability classifier.
|
|
30
|
+
- **Display label comes from the org.** `GenieAdmin` renders as "Data Cloud
|
|
31
|
+
Architect" on some orgs and "Data Cloud Admin" on others — the classifier
|
|
32
|
+
prefers the row's own `Label` and falls back to the canonical label only when
|
|
33
|
+
the row is absent. Never hard-code the label in user-facing text.
|
|
34
|
+
- **`needsPsl` is per row, from `LicenseId`.** The PSL POST uses the selected
|
|
35
|
+
tier's own `LicenseId` as `PermissionSetLicenseId` — PSL *names* above are for
|
|
36
|
+
human orientation only and are never queried by name in the write path.
|
|
37
|
+
- **Unified Catalog user tier = `UnifiedCatalogCommunityUser`, not `UnifiedCatalogAgent`.**
|
|
38
|
+
The three shipped standard permsets and their productized `Description` are:
|
|
39
|
+
`UnifiedCatalogAgent` = "Enables the **agent** to run service process" (the
|
|
40
|
+
agent's own bot-runtime identity — a machine tier, not a human one);
|
|
41
|
+
`UnifiedCatalogCommunityUser` = "Enables the **Community User** to **run**
|
|
42
|
+
unified catalog service process" (the human RUN tier — what a user, including a
|
|
43
|
+
Unified Employee user, assigns to exercise the agent's Unified Catalog actions);
|
|
44
|
+
`UnifiedCatalogAdmin` = "Enables the user to **setup** unified catalog" (the
|
|
45
|
+
admin/config tier). There is no plain `UnifiedCatalogUser`. So the human tiers
|
|
46
|
+
are `UnifiedCatalogCommunityUser` (use) + `UnifiedCatalogAdmin` (admin);
|
|
47
|
+
`UnifiedCatalogAgent` is deliberately excluded (it belongs to the agent's own
|
|
48
|
+
user, provisioned elsewhere, not to the human being granted access here).
|
|
49
|
+
- `DataCloudAISpecialist` also exists but is not one of this skill's tiers.
|
|
50
|
+
- **Unified Catalog tiers are license-SHAPE gated per target user.** Unlike Prompt
|
|
51
|
+
Templates and Data Cloud (offered to any user), the two Unified Catalog PSLs can
|
|
52
|
+
only be held by specific cohorts: `UnifiedCatalogCommunityUser` (the Community
|
|
53
|
+
User / use tier) requires a **Unified Employee** license, and `UnifiedCatalogAdmin`
|
|
54
|
+
(the Admin tier) is meaningful only for a **System Administrator**. Offering a UC
|
|
55
|
+
tier to a user whose license/profile can't hold it is a hard write-time failure
|
|
56
|
+
(a license-shape limit, not a seat shortage — retrying won't help). So
|
|
57
|
+
`scripts/gate-unified-catalog-tiers.mjs` runs per target user and offers the
|
|
58
|
+
Community User tier only to a Unified Employee user, the Admin tier only to a
|
|
59
|
+
System Administrator, and **omits Unified Catalog entirely** for any other user
|
|
60
|
+
(reported "not applicable for this user's license/profile — skipped", never a
|
|
61
|
+
failed write). This gate is Unified-Catalog-specific; the other two features are
|
|
62
|
+
not cohort-gated.
|
|
63
|
+
|
|
64
|
+
### Fixed-lookup discovery query (Phase 1)
|
|
65
|
+
|
|
66
|
+
```sql
|
|
67
|
+
SELECT Id, Name, Label, LicenseId
|
|
68
|
+
FROM PermissionSet
|
|
69
|
+
WHERE Name IN (
|
|
70
|
+
'EinsteinGPTPromptTemplateUser',
|
|
71
|
+
'EinsteinGPTPromptTemplateManager',
|
|
72
|
+
'GenieUserEnhancedSecurity',
|
|
73
|
+
'GenieAdmin',
|
|
74
|
+
'UnifiedCatalogCommunityUser',
|
|
75
|
+
'UnifiedCatalogAdmin'
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 2. Agent access via `Agent_Access` + `SetupEntityAccess`
|
|
80
|
+
|
|
81
|
+
An Agentforce / NGA agent is a **`BotDefinition`** record with
|
|
82
|
+
`Type = 'InternalCopilot'`. A permission set grants access to a specific agent
|
|
83
|
+
through a **`SetupEntityAccess`** row — exactly like granting Apex-class access:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
SetupEntityAccess {
|
|
87
|
+
ParentId: <permission set Id>, // the Agent_Access permset
|
|
88
|
+
SetupEntityId: <BotDefinition Id> // the agent (0Xx… key prefix)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Load-bearing details (verified via `sf sobject describe`)
|
|
93
|
+
|
|
94
|
+
- **`PermissionSet` is createable over the standard data API** (`createable:true`)
|
|
95
|
+
with just `Name` + `Label`. Create `Agent_Access` with a POST to
|
|
96
|
+
`/sobjects/PermissionSet` — no Tooling API, no Metadata XML, no deploy.
|
|
97
|
+
- **`SetupEntityAccess` is createable** with `ParentId` + `SetupEntityId`
|
|
98
|
+
(both required, both `createable:true`).
|
|
99
|
+
- **`SetupEntityType` is NOT createable** (`createable:false`, picklist). It is
|
|
100
|
+
derived from the `SetupEntityId` key prefix (`0Xx` → `BotDefinition`). Sending
|
|
101
|
+
it in the POST body errors — omit it. It IS filterable on the read, so the
|
|
102
|
+
idempotency query uses `WHERE ... AND SetupEntityType='BotDefinition'`.
|
|
103
|
+
- `SetupEntityAccess` is **not updateable** — grants are add/remove only, so the
|
|
104
|
+
idempotent path is "read existing grants, add the missing ones".
|
|
105
|
+
|
|
106
|
+
### Activated-agent discovery query (Phase 1)
|
|
107
|
+
|
|
108
|
+
Only agents with an **active** version should be offered — a draft/inactive
|
|
109
|
+
agent has nothing to exercise yet:
|
|
110
|
+
|
|
111
|
+
```sql
|
|
112
|
+
SELECT Id, DeveloperName, MasterLabel,
|
|
113
|
+
(SELECT Status FROM BotVersions WHERE Status='Active')
|
|
114
|
+
FROM BotDefinition
|
|
115
|
+
WHERE Type='InternalCopilot'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
An agent is activated iff its `BotVersions` child subquery returns ≥1 row.
|
|
119
|
+
|
|
120
|
+
## Codesearch / verification note
|
|
121
|
+
|
|
122
|
+
The feature-permset matrix and the `SetupEntityAccess`/`BotDefinition` mechanism
|
|
123
|
+
were verified live. The Unified Catalog **user** tier was corrected from
|
|
124
|
+
`UnifiedCatalogAgent` to `UnifiedCatalogCommunityUser` after the shipped
|
|
125
|
+
`PermissionSet.Description` fields showed `UnifiedCatalogAgent` is the agent's own
|
|
126
|
+
bot-runtime permset ("Enables the agent to run service process"), while
|
|
127
|
+
`UnifiedCatalogCommunityUser` is the human run tier ("Enables the Community User
|
|
128
|
+
to run unified catalog service process"). If the shipped permset Names, their
|
|
129
|
+
`Description`, or the `SetupEntityAccess` create-field set drift on a future
|
|
130
|
+
release, re-verify with `sf sobject describe --sobject SetupEntityAccess` and
|
|
131
|
+
`SELECT Name, Label, Description, LicenseId FROM PermissionSet WHERE Name LIKE 'UnifiedCatalog%'`
|
|
132
|
+
before changing the fixed lists in `scripts/`.
|