@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
|
@@ -3,51 +3,67 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Idempotency for this flow is keyed PRIMARILY on the TEMPLATE's own
|
|
5
5
|
// `botDefinitionId` — the platform's authoritative link from an `agent-templates`
|
|
6
|
-
// row to the live `BotDefinition` it was instantiated into — and FALLS BACK
|
|
7
|
-
//
|
|
6
|
+
// row to the live `BotDefinition` it was instantiated into — and FALLS BACK
|
|
7
|
+
// first to the BotDefinition's own `AgentTemplate` field (the OOTB, namespaced
|
|
8
|
+
// template API name it was instantiated from, e.g.
|
|
9
|
+
// `svc_itsm_intelligence__ITSrvcMgmtFulfiller`), then to a `DeveloperName`-keyed
|
|
10
|
+
// read.
|
|
8
11
|
// If the Fulfiller template was already instantiated under a DeveloperName that
|
|
9
12
|
// differs from this skill's default collected `IT_Service_Fulfiller_Agent`, a
|
|
10
13
|
// DeveloperName-only read false-negatives (exists:false) and the create then
|
|
11
|
-
// collides on `apiName` with `DUPLICATE_VALUE`
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
14
|
+
// collides on `apiName` with `DUPLICATE_VALUE`. `AgentTemplate` closes that gap
|
|
15
|
+
// far more reliably than a display name would: it is the platform-stamped source
|
|
16
|
+
// template on the live BotDefinition, so it survives any DeveloperName rename and
|
|
17
|
+
// carries the namespace prefix the skill already knows (preflight `template.id`).
|
|
18
|
+
// The template-row `botDefinitionId` is back-filled ONLY for platform-
|
|
19
|
+
// pre-provisioned agents (the ITSM create path never stamps `templateName`, so
|
|
20
|
+
// the platform never joins the agent-templates row to its BotDefinition), and the
|
|
21
|
+
// Fulfiller is never pre-provisioned — so its template `botDefinitionId` is null
|
|
22
|
+
// on the first run and every run after. Self-created Fulfiller agents also carry
|
|
23
|
+
// a NULL `AgentTemplate` (the create path doesn't stamp the source template), so
|
|
24
|
+
// for the Fulfiller the DeveloperName-keyed read is the guard that actually
|
|
25
|
+
// protects this path; `AgentTemplate` is a defensive key that would catch a
|
|
26
|
+
// hypothetical pre-provisioned Fulfiller and keeps this classifier identical to
|
|
27
|
+
// the Employee one (where `AgentTemplate` IS the load-bearing catcher). (Preflight
|
|
28
|
+
// emits `template.botDefinitionId`, `template.id`, and the collected
|
|
29
|
+
// developerName; the workflow passes the botDefinitionId as the primary key,
|
|
30
|
+
// template.id as the AgentTemplate key, and the developerName as the fallback.)
|
|
20
31
|
//
|
|
21
32
|
// This classifier consumes the raw JSON of a `sf data query ... --json` read of
|
|
22
|
-
// BotDefinition (BY Id primarily, BY DeveloperName on the
|
|
33
|
+
// BotDefinition (BY Id primarily, BY AgentTemplate then DeveloperName on the
|
|
34
|
+
// fallback) and decides
|
|
23
35
|
// whether the agent already exists — and if so, whether its latest BotVersion is
|
|
24
36
|
// Inactive (so the workflow can offer to activate it instead of creating a
|
|
25
37
|
// duplicate). This is the deterministic decision that gates whether the write is
|
|
26
38
|
// skipped — it MUST NOT be interpreted by the model in prose (authoring standard A9).
|
|
27
39
|
//
|
|
28
40
|
// Usage:
|
|
29
|
-
// node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName]
|
|
41
|
+
// node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName] [agentTemplate]
|
|
30
42
|
//
|
|
31
43
|
// When <botDefinitionId> is empty, `-`, or the literal `null`/`undefined` (the
|
|
32
44
|
// matched template carries no botDefinitionId), the classifier FALLS BACK to
|
|
33
|
-
// keying on <
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
45
|
+
// keying on <agentTemplate> (the source template API name), and then to
|
|
46
|
+
// <developerName> when the AgentTemplate misses too. <bot-query.json> must
|
|
47
|
+
// therefore be a read that ORs all three keys together: self-created agents are
|
|
48
|
+
// never back-filled with a botDefinitionId AND carry a null AgentTemplate (the
|
|
49
|
+
// ITSM create path doesn't stamp `templateName`), so DeveloperName is their only
|
|
50
|
+
// idempotency guard; a pre-provisioned agent whose live DeveloperName differs from
|
|
51
|
+
// this skill's collected guess is caught by AgentTemplate. Only when ALL of
|
|
52
|
+
// <botDefinitionId>, <agentTemplate>, and <developerName> are absent is
|
|
53
|
+
// exists:false emitted without reading a query file. Otherwise <bot-query.json> is
|
|
54
|
+
// a FILE PATH to the stdout captured from:
|
|
55
|
+
// sf data query -q "SELECT Id,DeveloperName,MasterLabel,AgentTemplate,
|
|
42
56
|
// (SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1)
|
|
43
|
-
// FROM BotDefinition WHERE Id='<botDefinitionId>' OR
|
|
57
|
+
// FROM BotDefinition WHERE Id='<botDefinitionId>' OR AgentTemplate='<agentTemplate>'
|
|
58
|
+
// OR DeveloperName='<developerName>'" \
|
|
44
59
|
// --target-org <org> --json > file.json
|
|
45
|
-
// (The present-id read ORs in DeveloperName so a DANGLING
|
|
46
|
-
// link — a botDefinitionId whose target BotDefinition was
|
|
47
|
-
// surfaces the live
|
|
48
|
-
//
|
|
49
|
-
// the template row carries no botDefinitionId at
|
|
50
|
-
// `DeveloperName='<developerName>'
|
|
60
|
+
// (The present-id read ORs in AgentTemplate AND DeveloperName so a DANGLING
|
|
61
|
+
// template→BotDefinition link — a botDefinitionId whose target BotDefinition was
|
|
62
|
+
// since deleted — still surfaces the live agent: the classifier tries the Id
|
|
63
|
+
// first, then the AgentTemplate, then the DeveloperName on the SAME records. The
|
|
64
|
+
// pure FALLBACK read, taken when the template row carries no botDefinitionId at
|
|
65
|
+
// all, keys on `AgentTemplate='<agentTemplate>' OR DeveloperName='<developerName>'`;
|
|
66
|
+
// everything else is identical.
|
|
51
67
|
// `sf data query --json` wraps results in a `.result.records[]` envelope. The
|
|
52
68
|
// BotVersions subquery is required so this classifier can see the latest
|
|
53
69
|
// version's Status — a query without it leaves latestVersionStatus null and
|
|
@@ -62,16 +78,17 @@
|
|
|
62
78
|
// child row was returned), and needsActivation is true only when exists is true
|
|
63
79
|
// AND latestVersionStatus is "Inactive" — the signal to offer activating the
|
|
64
80
|
// existing version instead of creating a new agent. `matchedBy` is
|
|
65
|
-
// "botDefinitionId" | "developerName" | null, recording which
|
|
81
|
+
// "botDefinitionId" | "agentTemplate" | "developerName" | null, recording which
|
|
82
|
+
// key hit. Exit code
|
|
66
83
|
// is always 0 on a parseable body (or when neither key is supplied); the verdict
|
|
67
84
|
// is carried in the payload. On an unparseable/failed query it exits 3 so the
|
|
68
85
|
// workflow surfaces the raw error rather than assuming NOT-EXISTS.
|
|
69
86
|
|
|
70
87
|
import { readFileSync } from 'node:fs';
|
|
71
88
|
|
|
72
|
-
const [queryPath, rawBotDefinitionId, rawDeveloperName] = process.argv.slice(2);
|
|
89
|
+
const [queryPath, rawBotDefinitionId, rawDeveloperName, rawAgentTemplate] = process.argv.slice(2);
|
|
73
90
|
if (!queryPath) {
|
|
74
|
-
process.stderr.write('usage: node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName]\n');
|
|
91
|
+
process.stderr.write('usage: node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName] [agentTemplate]\n');
|
|
75
92
|
process.exit(2);
|
|
76
93
|
}
|
|
77
94
|
|
|
@@ -89,8 +106,10 @@ function notSet(v) {
|
|
|
89
106
|
|
|
90
107
|
const botDefinitionId = String(rawBotDefinitionId ?? '').trim();
|
|
91
108
|
const developerName = String(rawDeveloperName ?? '').trim();
|
|
109
|
+
const agentTemplate = String(rawAgentTemplate ?? '').trim();
|
|
92
110
|
const noId = notSet(botDefinitionId);
|
|
93
111
|
const noName = notSet(developerName);
|
|
112
|
+
const noTemplate = notSet(agentTemplate);
|
|
94
113
|
|
|
95
114
|
const NOT_EXISTS = {
|
|
96
115
|
exists: false,
|
|
@@ -104,11 +123,12 @@ const NOT_EXISTS = {
|
|
|
104
123
|
needsActivation: false,
|
|
105
124
|
};
|
|
106
125
|
|
|
107
|
-
// Nothing to key on — no botDefinitionId AND no
|
|
108
|
-
// no way to detect an existing agent, so this is
|
|
109
|
-
// should always pass the collected developerName
|
|
110
|
-
//
|
|
111
|
-
|
|
126
|
+
// Nothing to key on — no botDefinitionId AND no AgentTemplate fallback AND no
|
|
127
|
+
// DeveloperName fallback. There is no way to detect an existing agent, so this is
|
|
128
|
+
// the create path. (The workflow should always pass the collected developerName
|
|
129
|
+
// and the template's id/AgentTemplate so the fallbacks below can run; this bare
|
|
130
|
+
// branch only fires when none of the three keys is supplied.)
|
|
131
|
+
if (noId && noTemplate && noName) {
|
|
112
132
|
process.stdout.write(JSON.stringify(NOT_EXISTS, null, 2) + '\n');
|
|
113
133
|
process.exit(0);
|
|
114
134
|
}
|
|
@@ -139,20 +159,22 @@ const records = Array.isArray(data.result?.records) ? data.result.records : [];
|
|
|
139
159
|
// `templateName`), so in practice the DeveloperName fallback below is what fires.
|
|
140
160
|
// The matching LOGIC here is kept identical to the Employee classifier on
|
|
141
161
|
// purpose — one shared matching contract, so the two can't drift and a future
|
|
142
|
-
// platform change that DOES populate the Fulfiller's botDefinitionId
|
|
143
|
-
// correctly rather than silently mismatched; see that script's header
|
|
144
|
-
// pre-provisioned rationale it exercises.
|
|
145
|
-
// FALLBACK: the
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
162
|
+
// platform change that DOES populate the Fulfiller's botDefinitionId/AgentTemplate
|
|
163
|
+
// is handled correctly rather than silently mismatched; see that script's header
|
|
164
|
+
// for the pre-provisioned rationale it exercises.
|
|
165
|
+
// FALLBACK: the BotDefinition's own `AgentTemplate`, then the collected
|
|
166
|
+
// DeveloperName. `AgentTemplate` is the OOTB source-template API name the platform
|
|
167
|
+
// stamps on a template-instantiated agent — the reliable "an agent from THIS
|
|
168
|
+
// template already exists" signal for pre-provisioned agents, independent of any
|
|
169
|
+
// DeveloperName rename. Self-created agents are NOT stamped (the ITSM create path
|
|
170
|
+
// never sets `templateName`), so their `AgentTemplate` is null and DeveloperName
|
|
171
|
+
// is their guard. We ALSO fall back this way when a PRESENT botDefinitionId
|
|
150
172
|
// matches nothing (a dangling link whose target BotDefinition was deleted): the
|
|
151
|
-
// present-id Phase-2 SOQL reads `WHERE Id=... OR
|
|
152
|
-
// link still surfaces the live
|
|
153
|
-
// create path and colliding with DUPLICATE_VALUE. Try the
|
|
154
|
-
// name; each filter is self-checking on top
|
|
155
|
-
// read can't false-positive.
|
|
173
|
+
// present-id Phase-2 SOQL reads `WHERE Id=... OR AgentTemplate=... OR
|
|
174
|
+
// DeveloperName=...`, so a stale link still surfaces the live agent instead of
|
|
175
|
+
// slipping through to the create path and colliding with DUPLICATE_VALUE. Try the
|
|
176
|
+
// Id first, then the template, then the name; each filter is self-checking on top
|
|
177
|
+
// of the SOQL WHERE so a wrong-keyed read can't false-positive.
|
|
156
178
|
let matches = [];
|
|
157
179
|
let matchedBy = null;
|
|
158
180
|
if (!noId) {
|
|
@@ -160,12 +182,38 @@ if (!noId) {
|
|
|
160
182
|
matches = records.filter((r) => idKey(r?.Id) === wantedIdKey);
|
|
161
183
|
if (matches.length) matchedBy = 'botDefinitionId';
|
|
162
184
|
}
|
|
185
|
+
// FIRST FALLBACK: the BotDefinition's `AgentTemplate` (source template API name).
|
|
186
|
+
// When a live agent was instantiated from this template under a DeveloperName
|
|
187
|
+
// that differs from this skill's collected guess AND its template row carries no
|
|
188
|
+
// botDefinitionId, the Id and DeveloperName keys both miss and the create then
|
|
189
|
+
// collides with DUPLICATE_VALUE. `AgentTemplate` is the platform-stamped source
|
|
190
|
+
// template, so matching on it recovers that live agent reliably. SOQL text
|
|
191
|
+
// comparison is case-insensitive, so compare the same way. `AgentTemplate` is NOT
|
|
192
|
+
// unique (a template can be instantiated more than once), so if more than one
|
|
193
|
+
// record shares it we keep them all but surface an Active version first (see
|
|
194
|
+
// below) — the report should treat the already-active one as the real match.
|
|
195
|
+
if (!matches.length && !noTemplate) {
|
|
196
|
+
const wantedTemplate = agentTemplate.toLowerCase();
|
|
197
|
+
matches = records.filter((r) => String(r?.AgentTemplate ?? '').trim().toLowerCase() === wantedTemplate);
|
|
198
|
+
if (matches.length) matchedBy = 'agentTemplate';
|
|
199
|
+
}
|
|
200
|
+
// SECOND FALLBACK: the collected DeveloperName — the guard for self-created agents
|
|
201
|
+
// (null AgentTemplate). DeveloperName uniqueness is case-insensitive; compare
|
|
202
|
+
// accordingly.
|
|
163
203
|
if (!matches.length && !noName) {
|
|
164
|
-
// DeveloperName uniqueness is case-insensitive; compare accordingly.
|
|
165
204
|
const wantedName = developerName.toLowerCase();
|
|
166
205
|
matches = records.filter((r) => String(r?.DeveloperName ?? '').trim().toLowerCase() === wantedName);
|
|
167
206
|
if (matches.length) matchedBy = 'developerName';
|
|
168
207
|
}
|
|
208
|
+
if (matchedBy === 'agentTemplate' && matches.length > 1) {
|
|
209
|
+
// Prefer a record whose latest BotVersion is Active so `matches[0]` (used for
|
|
210
|
+
// latestVersion/agentId below) reflects the live agent rather than a stale draft.
|
|
211
|
+
matches = [...matches].sort((a, b) => {
|
|
212
|
+
const aActive = a?.BotVersions?.records?.[0]?.Status === 'Active' ? 0 : 1;
|
|
213
|
+
const bActive = b?.BotVersions?.records?.[0]?.Status === 'Active' ? 0 : 1;
|
|
214
|
+
return aActive - bActive;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
169
217
|
const exists = matches.length > 0;
|
|
170
218
|
|
|
171
219
|
// The BotVersions child subquery (if present in the SOQL) surfaces the latest
|
|
@@ -180,12 +228,15 @@ const needsActivation = exists && latestVersionStatus === 'Inactive';
|
|
|
180
228
|
process.stdout.write(JSON.stringify({
|
|
181
229
|
exists,
|
|
182
230
|
count: matches.length,
|
|
183
|
-
// Which key matched — `botDefinitionId` (primary)
|
|
184
|
-
//
|
|
231
|
+
// Which key matched — `botDefinitionId` (primary), `agentTemplate` (the
|
|
232
|
+
// reliable catcher for a pre-provisioned agent whose DeveloperName differs from
|
|
233
|
+
// the collected guess), or `developerName` (the fallback for self-created
|
|
234
|
+
// agents). null when nothing matched.
|
|
185
235
|
matchedBy: exists ? matchedBy : null,
|
|
186
236
|
agentId: exists ? (matches[0].Id ?? null) : null,
|
|
187
|
-
// On
|
|
188
|
-
// template row was missing; on the Id path it echoes the
|
|
237
|
+
// On an AgentTemplate- or DeveloperName-fallback hit this surfaces the live
|
|
238
|
+
// BotDefinition Id the template row was missing; on the Id path it echoes the
|
|
239
|
+
// queried id.
|
|
189
240
|
botDefinitionId: exists ? (matches[0].Id ?? null) : (noId ? null : botDefinitionId),
|
|
190
241
|
developerName: exists ? (matches[0].DeveloperName ?? null) : null,
|
|
191
242
|
latestVersionId: latestVersion?.Id ?? null,
|
package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs
CHANGED
|
@@ -20,12 +20,17 @@
|
|
|
20
20
|
//
|
|
21
21
|
// Emits a single JSON object to stdout:
|
|
22
22
|
// { studio: { hasAccess, signal, reason },
|
|
23
|
-
// template: { present, id, hasAgentScript, botDefinitionId, signal, reason },
|
|
23
|
+
// template: { present, id, hasAgentScript, botDefinitionId, masterLabel, signal, reason },
|
|
24
24
|
// verdict, reasons: [...] }
|
|
25
25
|
// `botDefinitionId` is copied from the matched agent-templates row and passed to
|
|
26
26
|
// the Phase-2 idempotency read as the PRIMARY key (the platform's authoritative
|
|
27
|
-
// template→BotDefinition link); the
|
|
28
|
-
//
|
|
27
|
+
// template→BotDefinition link); `id` (the template's OOTB namespaced API name) is
|
|
28
|
+
// passed as the AgentTemplate fallback key — it matches `BotDefinition.AgentTemplate`
|
|
29
|
+
// on a template-instantiated agent regardless of its DeveloperName — and the
|
|
30
|
+
// collected developerName is the last fallback (the guard for self-created agents,
|
|
31
|
+
// which carry a null AgentTemplate). `masterLabel` is echoed only for the report's
|
|
32
|
+
// display label; it is NOT an idempotency key (a display name is renamable and
|
|
33
|
+
// non-unique). See classify-agent-existence.mjs for why. (The template row's
|
|
29
34
|
// `isInstalled`/`isActivated` flags are NOT emitted: they ride the same
|
|
30
35
|
// AgentTemplate join as botDefinitionId, so for agents this skill creates — which
|
|
31
36
|
// never stamp `templateName` — they read false even after the agent exists, and
|
|
@@ -107,16 +112,18 @@ function classifyTemplate(res, masterLabel) {
|
|
|
107
112
|
}
|
|
108
113
|
// Idempotency identity carried by the matched row — the platform's own link
|
|
109
114
|
// from this template to the BotDefinition it was instantiated into. A populated
|
|
110
|
-
// botDefinitionId is
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
// skill
|
|
114
|
-
//
|
|
115
|
+
// botDefinitionId is a direct link for PRE-PROVISIONED agents; when it is null,
|
|
116
|
+
// the template's own `id` (matched against `BotDefinition.AgentTemplate` in
|
|
117
|
+
// Phase 2) still catches a pre-provisioned agent regardless of what DeveloperName
|
|
118
|
+
// this skill would have guessed (see classify-agent-existence.mjs). Agents this
|
|
119
|
+
// skill creates never stamp `templateName`, so they carry BOTH a null row
|
|
120
|
+
// botDefinitionId AND a null AgentTemplate — the Phase-2 read falls back to the
|
|
121
|
+
// collected DeveloperName key for that case.
|
|
115
122
|
const botDefinitionId = typeof match.botDefinitionId === 'string' && match.botDefinitionId.trim() ? match.botDefinitionId : null;
|
|
116
123
|
if (!match.agentScript || typeof match.agentScript !== 'string' || !match.agentScript.trim()) {
|
|
117
124
|
return { present: true, id: match.id ?? null, hasAgentScript: false, botDefinitionId, signal: 'CANNOT-CONFIRM', reason: `Matched "${masterLabel}" (id=${match.id}) but it had no agentScript field — the NGA bundle create needs the template's Agent Script content.` };
|
|
118
125
|
}
|
|
119
|
-
return { present: true, id: match.id ?? null, hasAgentScript: true, botDefinitionId, signal: 'PASS', reason: `Template "${masterLabel}" present (id=${match.id}) with a non-empty agentScript${botDefinitionId ? `; already instantiated (botDefinitionId=${botDefinitionId})` : '; not yet instantiated (no botDefinitionId — the Phase-2 read
|
|
126
|
+
return { present: true, id: match.id ?? null, hasAgentScript: true, botDefinitionId, signal: 'PASS', reason: `Template "${masterLabel}" present (id=${match.id}) with a non-empty agentScript${botDefinitionId ? `; already instantiated (botDefinitionId=${botDefinitionId})` : '; not yet instantiated (no botDefinitionId — the Phase-2 read keys on AgentTemplate=id, then DeveloperName)'} — feed it to scripts/build-create-body.mjs for the NGA bundle create.` };
|
|
120
127
|
}
|
|
121
128
|
|
|
122
129
|
const [studioPath, templatePath, rawLabel] = process.argv.slice(2);
|
|
@@ -145,11 +152,18 @@ process.stdout.write(JSON.stringify({
|
|
|
145
152
|
id: template.id,
|
|
146
153
|
hasAgentScript: template.hasAgentScript,
|
|
147
154
|
// Idempotency identity (from the matched agent-templates row): the Phase-2
|
|
148
|
-
// read uses botDefinitionId as the PRIMARY key
|
|
149
|
-
// as the
|
|
150
|
-
//
|
|
151
|
-
// template row was never joined (e.g. a self-created
|
|
155
|
+
// read uses botDefinitionId as the PRIMARY key, `id` (the template's namespaced
|
|
156
|
+
// API name) as the AgentTemplate key, and the collected developerName as the
|
|
157
|
+
// last fallback. A populated botDefinitionId is a direct "agent already exists"
|
|
158
|
+
// link; null just means this template row was never joined (e.g. a self-created
|
|
159
|
+
// agent) — not "no agent". `id` is the reliable catcher for a pre-provisioned
|
|
160
|
+
// agent whose DeveloperName differs from this skill's collected guess: it
|
|
161
|
+
// matches `BotDefinition.AgentTemplate`, the platform-stamped source template.
|
|
162
|
+
// `masterLabel` is echoed only for the report's display label (NOT an
|
|
163
|
+
// idempotency key). The workflow passes botDefinitionId, `id`, and the collected
|
|
164
|
+
// developerName to classify-agent-existence.mjs from this single source.
|
|
152
165
|
botDefinitionId: template.botDefinitionId ?? null,
|
|
166
|
+
masterLabel,
|
|
153
167
|
signal: template.signal,
|
|
154
168
|
reason: template.reason,
|
|
155
169
|
},
|
package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs
CHANGED
|
@@ -144,13 +144,19 @@ if (
|
|
|
144
144
|
|
|
145
145
|
const reason = String(state.reason ?? '').trim();
|
|
146
146
|
|
|
147
|
+
// The "set up access" next step below is the handoff to the
|
|
148
|
+
// `service-itsm-agentic-setup-agent-runtime-access-assign` skill (declared in
|
|
149
|
+
// this skill's metadata.relatedSkills). We deliberately surface it in plain
|
|
150
|
+
// admin language ("grant this agent's runtime access") rather than by raw skill
|
|
151
|
+
// name — the routing metadata carries the linkage, so the user-facing report
|
|
152
|
+
// stays friendly while the relationship remains discoverable.
|
|
147
153
|
const NEXT_STEPS = {
|
|
148
154
|
'CREATED':
|
|
149
|
-
'The IT Service Fulfiller agent is live as an NGA-native agent (no external-link icon in Agentforce Studio). No new agent was provisioned beyond the one just created. Verify end-to-end in Agentforce Studio\'s Agents list.',
|
|
155
|
+
'The IT Service Fulfiller agent is live as an NGA-native agent (no external-link icon in Agentforce Studio). No new agent was provisioned beyond the one just created. Verify end-to-end in Agentforce Studio\'s Agents list. **Next — set up access:** before anyone can use the agent, the user needs the runtime permissions the agent\'s actions use (Prompt Templates, Data Cloud, or Unified Catalog, depending on what is provisioned). Just ask to **grant this agent\'s runtime access** and those feature permissions — plus an "Agent Access" permission set covering the agent — will be set up for the user(s) you choose.',
|
|
150
156
|
'ALREADY-CREATED':
|
|
151
|
-
'The IT Service Fulfiller agent was already present and active — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list.',
|
|
157
|
+
'The IT Service Fulfiller agent was already present and active — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list. **Next — set up access:** before anyone can use the agent, the user needs the runtime permissions the agent\'s actions use (Prompt Templates, Data Cloud, or Unified Catalog, depending on what is provisioned). Just ask to **grant this agent\'s runtime access** and those feature permissions — plus an "Agent Access" permission set covering the agent — will be set up for the user(s) you choose.',
|
|
152
158
|
'ACTIVATED':
|
|
153
|
-
'The existing IT Service Fulfiller agent was found inactive and has been activated — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list.',
|
|
159
|
+
'The existing IT Service Fulfiller agent was found inactive and has been activated — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list. **Next — set up access:** before anyone can use the agent, the user needs the runtime permissions the agent\'s actions use (Prompt Templates, Data Cloud, or Unified Catalog, depending on what is provisioned). Just ask to **grant this agent\'s runtime access** and those feature permissions — plus an "Agent Access" permission set covering the agent — will be set up for the user(s) you choose.',
|
|
154
160
|
'PENDING CONFIRMATION':
|
|
155
161
|
'The run is paused at the confirm-to-write gate. In this skill, create + publish + activate happen as one atomic sequence gated by a single confirmation — there is no supported create-only or publish-without-activate mode, and no partial "create-only" mode of any kind. Re-run and reply "yes" when you are ready for the agent to go live.',
|
|
156
162
|
'DECLINED':
|