@salesforce/afv-skills 1.40.0 → 1.41.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/automation-flow-generate/SKILL.md +32 -43
- package/skills/experience-portal-create/SKILL.md +497 -0
- package/skills/experience-portal-create/assets/report-template.md +30 -0
- package/skills/experience-portal-create/references/mcp-invocation.md +288 -0
- package/skills/experience-portal-create/references/post-creation-activate-publish.md +165 -0
- package/skills/experience-portal-create/references/templates.md +253 -0
- package/skills/experience-ui-bundle-features-generate/SKILL.md +5 -1
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -0
- package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -0
- package/skills/platform-datamask-run/SKILL.md +345 -0
- package/skills/platform-datamask-run/references/api-surface.md +130 -0
- package/skills/platform-datamask-run/references/policy-authoring.md +185 -0
- package/skills/platform-datamask-run/references/run-and-abort.md +116 -0
- package/skills/platform-datamask-run/scripts/poll-job.sh +115 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +51 -3
- package/skills/platform-dataspace-access-configure/scripts/inspect-dataspace-scopes.sh +56 -0
- package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +1 -0
- package/skills/platform-sandbox-configure/SKILL.md +17 -2
- package/skills/platform-trial-org-create/SKILL.md +175 -0
- package/skills/platform-trial-org-create/examples/create_request.json +9 -0
- package/skills/platform-trial-org-create/examples/error_response.json +41 -0
- package/skills/platform-trial-org-create/examples/success_response.json +27 -0
- package/skills/platform-trial-org-create/references/error_codes.md +42 -0
- package/skills/platform-trial-org-create/references/signup_request_fields.md +69 -0
- package/skills/platform-trial-org-create/scripts/create_signup_request.sh +175 -0
- package/skills/platform-trial-org-create/scripts/get_signup_request.sh +155 -0
- package/skills/platform-widget-generate/SKILL.md +47 -6
- package/skills/platform-widget-generate/examples/conditional.json +3 -3
- package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
- package/skills/platform-widget-generate/examples/single-object.json +2 -2
- package/skills/platform-widget-generate/references/widget-bundle-layout.md +1 -1
- package/skills/service-agentforce-channel-configure/SKILL.md +271 -0
- package/skills/service-agentforce-channel-configure/references/agent-wiring.md +97 -0
- package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +145 -0
- package/skills/service-agentforce-channel-configure/references/channel-branch-voice.md +69 -0
- package/skills/service-agentforce-channel-configure/references/channel-types.md +61 -0
- package/skills/service-agentforce-channel-configure/references/live-traffic-gate.md +86 -0
- package/skills/service-agentforce-channel-configure/references/queue-resolution.md +135 -0
- package/skills/service-agentforce-channel-configure/references/routing-flow.md +384 -0
- package/skills/service-catalog-template-deploy/SKILL.md +310 -0
- package/skills/service-catalog-template-deploy/references/cli-invocation.md +258 -0
- package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +164 -0
- package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +94 -0
- package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +331 -0
- package/skills/service-catalog-template-search/SKILL.md +212 -0
- package/skills/service-catalog-template-search/references/cli-invocation.md +128 -0
- package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +205 -0
- package/skills/service-concierge-portal-generate/SKILL.md +126 -0
- package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1428 -0
- package/skills/service-digital-engagement-channel-configure/SKILL.md +46 -6
- package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +2 -1
- package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -1
- package/skills/service-helpagent-coordinate/README.md +8 -2
- package/skills/service-helpagent-coordinate/SKILL.md +126 -130
- package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +70 -53
- package/skills/service-helpagent-coordinate/references/agent-script.md +571 -457
- package/skills/service-helpagent-coordinate/references/channel-voice.md +38 -9
- package/skills/service-helpagent-coordinate/references/channel-web-chat.md +173 -49
- package/skills/service-helpagent-coordinate/references/output-report-format.md +126 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +153 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +79 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +35 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +271 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +265 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +220 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-final-report.mjs +102 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/record-enable-result.mjs +73 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +206 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +194 -0
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +223 -0
- package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +45 -7
- package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +45 -5
- package/skills/service-itsm-agentic-setup-configure/SKILL.md +116 -0
- package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +64 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +158 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +361 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/error-taxonomy.md +44 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +66 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +66 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/specialized-templates.md +148 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +169 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/build-create-body.mjs +116 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +185 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +168 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/create-scratch-dir.mjs +58 -0
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +197 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +186 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +51 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +345 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/error-taxonomy.md +44 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +63 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +44 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +149 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +110 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +201 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-activate-result.mjs +135 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +194 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +158 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/create-scratch-dir.mjs +58 -0
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +191 -0
- package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +133 -0
- package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +71 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +308 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +23 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +193 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +57 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +394 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +266 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +106 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +142 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +82 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-action-surface.mjs +137 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-assignment-state.mjs +99 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +120 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/resolve-target-user.mjs +86 -0
- package/skills/service-itsm-agentic-setup-uel-user-create/SKILL.md +284 -0
- package/skills/service-itsm-agentic-setup-uel-user-create/references/mcp-invocation.md +302 -0
- package/skills/service-itsm-channels-coordinate/SKILL.md +472 -0
- package/skills/service-itsm-incident-mgmt-configure/SKILL.md +212 -0
- package/skills/service-itsm-incident-mgmt-configure/references/mcp-invocation.md +225 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +53 -12
- package/skills/service-itsm-swarming-configure/SKILL.md +212 -0
- package/skills/service-itsm-teams-configure/SKILL.md +395 -0
- package/skills/service-itsm-teams-configure/references/azure-credential-population.md +213 -0
- package/skills/service-itsm-teams-configure/references/gotchas.md +23 -0
- package/skills/service-itsm-teams-coordinate/SKILL.md +175 -0
- package/skills/service-itsm-teams-coordinate/examples/output-templates.md +85 -0
- package/skills/service-itsm-teams-debug/SKILL.md +144 -0
- package/skills/service-itsm-teams-debug/references/configuration-checklists.md +277 -0
- package/skills/service-itsm-teams-debug/references/report-generation.md +95 -0
- package/skills/service-itsm-teams-employee-agent-configure/SKILL.md +139 -0
- package/skills/service-itsm-teams-employee-agent-configure/assets/Teams_AgentForce.EmbeddedServiceConfig-meta.xml +43 -0
- package/skills/service-itsm-teams-employee-agent-configure/references/teams-embedded-employee-agent.md +480 -0
- package/skills/service-itsm-teams-itdesk-configure/SKILL.md +232 -0
- package/skills/service-itsm-teams-itservice-configure/SKILL.md +391 -0
package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deterministic preflight classifier for the Employee-agent create flow.
|
|
3
|
+
//
|
|
4
|
+
// Two fixed JSON-parsing / decision rules that must not live in model prose
|
|
5
|
+
// (authoring standard A9):
|
|
6
|
+
// 1. Studio access: read `hasAccess` from the agentforce-studio/access/Agents
|
|
7
|
+
// body → PASS (true) / FAIL (false) / CANNOT-CONFIRM (404 / not wired).
|
|
8
|
+
// 2. Template provisioning: find the agent-templates item whose masterLabel
|
|
9
|
+
// matches the target ("IT Service Employee"), confirm it carries a non-empty
|
|
10
|
+
// `agentScript` (the Agent Script YAML fed into the NGA bundle create) → PRESENT
|
|
11
|
+
// (+hasAgentScript) / ABSENT (empty data[] or no match) / CANNOT-CONFIRM
|
|
12
|
+
// (404 / not wired).
|
|
13
|
+
//
|
|
14
|
+
// Usage:
|
|
15
|
+
// node classify-preflight.mjs <studio-access.json> <agent-templates.json> <masterLabel>
|
|
16
|
+
//
|
|
17
|
+
// Both file args are paths to raw `sf api request rest` stdout captures; the
|
|
18
|
+
// files may hold a Connect error array or be empty when the CLI exited non-zero.
|
|
19
|
+
// <masterLabel> is the template's display label (default "IT Service Employee").
|
|
20
|
+
//
|
|
21
|
+
// Emits a single JSON object to stdout:
|
|
22
|
+
// { studio: { hasAccess, signal, reason },
|
|
23
|
+
// template: { present, id, hasAgentScript, botDefinitionId, signal, reason },
|
|
24
|
+
// verdict, reasons: [...] }
|
|
25
|
+
// `botDefinitionId` is copied from the matched agent-templates row and passed to
|
|
26
|
+
// the Phase-2 idempotency read as the PRIMARY key (the platform's authoritative
|
|
27
|
+
// template→BotDefinition link); the collected developerName is the FALLBACK key
|
|
28
|
+
// there. See classify-agent-existence.mjs for why. (The template row's
|
|
29
|
+
// `isInstalled`/`isActivated` flags are NOT emitted: they ride the same
|
|
30
|
+
// AgentTemplate join as botDefinitionId, so for agents this skill creates — which
|
|
31
|
+
// never stamp `templateName` — they read false even after the agent exists, and
|
|
32
|
+
// nothing downstream consumes them.)
|
|
33
|
+
// where signal is PASS | FAIL | CANNOT-CONFIRM | ERROR and verdict is
|
|
34
|
+
// READY | NOT-READY | CANNOT-CONFIRM | ERROR. Exit is always 0 on usable args.
|
|
35
|
+
// ERROR (studio only) means the Studio-access read returned a parseable but
|
|
36
|
+
// non-404 error body (401/403/unexpected) — that is a failed prerequisite
|
|
37
|
+
// read, not an unwired gate, so it must stop the workflow rather than fall
|
|
38
|
+
// through to a CANNOT-CONFIRM that a present template can outrun to READY.
|
|
39
|
+
|
|
40
|
+
import { readFileSync } from 'node:fs';
|
|
41
|
+
|
|
42
|
+
function readJson(path) {
|
|
43
|
+
try {
|
|
44
|
+
const text = readFileSync(path, 'utf8').trim();
|
|
45
|
+
if (!text) return { ok: false };
|
|
46
|
+
return { ok: true, data: JSON.parse(text) };
|
|
47
|
+
} catch {
|
|
48
|
+
return { ok: false };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function asErrorArray(data) {
|
|
53
|
+
if (Array.isArray(data)) return data.filter((e) => e && (e.errorCode || e.message));
|
|
54
|
+
if (data && (data.errorCode || data.message)) return [data];
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isNotFoundError(data) {
|
|
59
|
+
return asErrorArray(data).some((e) => {
|
|
60
|
+
const code = String(e?.errorCode ?? '').toUpperCase();
|
|
61
|
+
const msg = String(e?.message ?? '').toUpperCase();
|
|
62
|
+
return code.includes('NOT_FOUND') || code.includes('NOT_EXIST') ||
|
|
63
|
+
msg.includes('NOT FOUND') || msg.includes('DOES NOT EXIST') ||
|
|
64
|
+
msg.includes('COULD NOT BE FOUND');
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function errorSnippet(errs) {
|
|
69
|
+
return errs.map((e) => `${e.errorCode ?? 'ERROR'}: ${e.message ?? ''}`.trim()).join(' | ').slice(0, 500);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function classifyStudio(res) {
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
return { hasAccess: null, signal: 'CANNOT-CONFIRM', reason: 'Studio access — no readable body (endpoint not wired / empty). A successful create/publish/activate is authoritative.' };
|
|
75
|
+
}
|
|
76
|
+
const d = res.data;
|
|
77
|
+
const errs = asErrorArray(d);
|
|
78
|
+
if (errs.length) {
|
|
79
|
+
if (isNotFoundError(d)) return { hasAccess: null, signal: 'CANNOT-CONFIRM', reason: 'Studio access → 404 (access-check gate not wired on this org). Treat as cannot-confirm; a successful create/publish/activate is authoritative.' };
|
|
80
|
+
return { hasAccess: null, signal: 'ERROR', reason: `Studio access read failed: ${errorSnippet(errs)} — surface the raw response and stop; do not treat as an unwired gate.` };
|
|
81
|
+
}
|
|
82
|
+
if (d?.hasAccess === true) return { hasAccess: true, signal: 'PASS', reason: 'Studio access → hasAccess=true.' };
|
|
83
|
+
if (d?.hasAccess === false) return { hasAccess: false, signal: 'FAIL', reason: 'Studio access → hasAccess=false — offer the prerequisite readiness hand-off before any write.' };
|
|
84
|
+
return { hasAccess: null, signal: 'CANNOT-CONFIRM', reason: 'Studio access body had no boolean hasAccess field.' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function classifyTemplate(res, masterLabel) {
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
return { present: false, id: null, hasAgentScript: false, signal: 'CANNOT-CONFIRM', reason: 'agent-templates — no readable body (endpoint not wired / empty).' };
|
|
90
|
+
}
|
|
91
|
+
const d = res.data;
|
|
92
|
+
if (asErrorArray(d).length) {
|
|
93
|
+
if (isNotFoundError(d)) return { present: false, id: null, hasAgentScript: false, signal: 'CANNOT-CONFIRM', reason: 'agent-templates → 404 (ITSM Connect namespace not provisioned). Hand off to the readiness check.' };
|
|
94
|
+
return { present: false, id: null, hasAgentScript: false, signal: 'CANNOT-CONFIRM', reason: 'agent-templates read returned an error body — surface it.' };
|
|
95
|
+
}
|
|
96
|
+
const items = Array.isArray(d?.data) ? d.data : null;
|
|
97
|
+
if (!items) return { present: false, id: null, hasAgentScript: false, signal: 'CANNOT-CONFIRM', reason: 'agent-templates had no data[] array (unexpected shape).' };
|
|
98
|
+
// Filter to the only namespace this skill instantiates. The endpoint also
|
|
99
|
+
// returns Fulfiller-side (`svc_itsm_intelligence__*`), Slack, ServiceNow,
|
|
100
|
+
// Runtime Insights, and other-namespace entries — some carry masterLabels
|
|
101
|
+
// that collide with in-namespace entries (e.g. `System Password Reset
|
|
102
|
+
// Assistance` exists in both `svc_emp_intelligence__` and `EmpSvcAgent__`).
|
|
103
|
+
// A `masterLabel`-only match would silently pick whichever appeared first
|
|
104
|
+
// in `data[]`; filtering first pins the choice to the correct namespace.
|
|
105
|
+
const inNamespace = items.filter((it) => typeof it?.id === 'string' && it.id.startsWith('svc_emp_intelligence__'));
|
|
106
|
+
const wanted = String(masterLabel).trim().toLowerCase();
|
|
107
|
+
const match = inNamespace.find((it) => String(it?.masterLabel ?? '').trim().toLowerCase() === wanted);
|
|
108
|
+
if (!match) {
|
|
109
|
+
return {
|
|
110
|
+
present: false, id: null, hasAgentScript: false, signal: 'FAIL',
|
|
111
|
+
reason: items.length === 0
|
|
112
|
+
? 'agent-templates returned an empty data[] — wrong agentType or the org is not ITSM-provisioned; hand off to the readiness check.'
|
|
113
|
+
: inNamespace.length === 0
|
|
114
|
+
? `agent-templates returned ${items.length} entries but none under the svc_emp_intelligence__ namespace — the Employee IT Service feature toggles are not provisioned on this org; hand off to the readiness check.`
|
|
115
|
+
: `No svc_emp_intelligence__ template with masterLabel "${masterLabel}" (got: ${inNamespace.map((i) => i?.masterLabel).filter(Boolean).join(', ') || 'none'}). Hand off to the readiness check.`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Idempotency identity carried by the matched row — the platform's own link
|
|
119
|
+
// from this template to the BotDefinition it was instantiated into. A populated
|
|
120
|
+
// botDefinitionId is the reliable idempotency signal for PRE-PROVISIONED agents
|
|
121
|
+
// (see classify-agent-existence.mjs): it means the agent already exists
|
|
122
|
+
// regardless of what DeveloperName this skill would have guessed. Agents this
|
|
123
|
+
// skill creates never stamp `templateName`, so their row's botDefinitionId stays
|
|
124
|
+
// null — the Phase-2 read falls back to a DeveloperName key for that case.
|
|
125
|
+
const botDefinitionId = typeof match.botDefinitionId === 'string' && match.botDefinitionId.trim() ? match.botDefinitionId : null;
|
|
126
|
+
if (!match.agentScript || typeof match.agentScript !== 'string' || !match.agentScript.trim()) {
|
|
127
|
+
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.` };
|
|
128
|
+
}
|
|
129
|
+
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 falls back to DeveloperName)'} — feed it to scripts/build-create-body.mjs for the NGA bundle create.` };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const [studioPath, templatePath, rawLabel] = process.argv.slice(2);
|
|
133
|
+
if (!studioPath || !templatePath) {
|
|
134
|
+
process.stderr.write('usage: node classify-preflight.mjs <studio-access.json> <agent-templates.json> [masterLabel]\n');
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
const masterLabel = rawLabel && rawLabel.trim() ? rawLabel : 'IT Service Employee';
|
|
138
|
+
|
|
139
|
+
const studio = classifyStudio(readJson(studioPath));
|
|
140
|
+
const template = classifyTemplate(readJson(templatePath), masterLabel);
|
|
141
|
+
|
|
142
|
+
// Verdict: the template MUST be present to create. Studio FALSE blocks (hand-off);
|
|
143
|
+
// Studio ERROR (non-404 failed read, e.g. 401/403) blocks — surface it, stop.
|
|
144
|
+
// Studio CANNOT-CONFIRM (confirmed 404 gate) does not block — create/publish/activate is authoritative.
|
|
145
|
+
let verdict;
|
|
146
|
+
if (studio.signal === 'ERROR') verdict = 'ERROR';
|
|
147
|
+
else if (studio.signal === 'FAIL' || template.signal === 'FAIL') verdict = 'NOT-READY';
|
|
148
|
+
else if (template.signal === 'PASS') verdict = 'READY'; // studio PASS, or unconfirmed via a documented 404 gate — template present is enough to attempt
|
|
149
|
+
else verdict = 'CANNOT-CONFIRM';
|
|
150
|
+
|
|
151
|
+
process.stdout.write(JSON.stringify({
|
|
152
|
+
studio: { hasAccess: studio.hasAccess, signal: studio.signal, reason: studio.reason },
|
|
153
|
+
template: {
|
|
154
|
+
present: template.present,
|
|
155
|
+
id: template.id,
|
|
156
|
+
hasAgentScript: template.hasAgentScript,
|
|
157
|
+
// Idempotency identity (from the matched agent-templates row): the Phase-2
|
|
158
|
+
// read uses botDefinitionId as the PRIMARY key and the collected developerName
|
|
159
|
+
// as the FALLBACK. A populated botDefinitionId is the load-bearing "agent
|
|
160
|
+
// already exists" signal for pre-provisioned agents; null just means this
|
|
161
|
+
// template row was never joined (e.g. a self-created agent) — not "no agent".
|
|
162
|
+
botDefinitionId: template.botDefinitionId ?? null,
|
|
163
|
+
signal: template.signal,
|
|
164
|
+
reason: template.reason,
|
|
165
|
+
},
|
|
166
|
+
verdict,
|
|
167
|
+
reasons: [studio.reason, template.reason],
|
|
168
|
+
}, null, 2) + '\n');
|
package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/create-scratch-dir.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deterministic Phase-0 scratch-directory creator for the Employee-agent
|
|
3
|
+
// create/activate flow.
|
|
4
|
+
//
|
|
5
|
+
// Phase-0 path selection + `mkdtemp` behavior are deterministic and must not
|
|
6
|
+
// live in workflow prose (authoring standard A9).
|
|
7
|
+
//
|
|
8
|
+
// The scratch dir MUST stay OUTSIDE the harness's scored `${outputDir}` tree.
|
|
9
|
+
// Several phases capture raw `sf api request rest` stdout, and that command is
|
|
10
|
+
// in beta — it prints beta/update/plugin diagnostics to STDERR. If an agent
|
|
11
|
+
// captures combined output (`2>&1`) instead of the documented `2>…err` split,
|
|
12
|
+
// that stderr preamble is merged into the captured file; a raw capture rooted
|
|
13
|
+
// under `${outputDir}` would then land in the eval's scored artifact set and
|
|
14
|
+
// fail the `core:json-valid` assertion even though the response body itself is
|
|
15
|
+
// well-formed JSON. So the scratch dir roots under `${TMPDIR}` (private,
|
|
16
|
+
// user-scoped), then `/tmp`, and only as an ultimate fallback (both temp bases
|
|
17
|
+
// unwritable) under the harness `${outputDir}`. `mkdtempSync` creates the run
|
|
18
|
+
// dir mode 0700 (owner-only) with a random suffix, so the world-writable `/tmp`
|
|
19
|
+
// parent is not a concern. Only the durable `${outputDir}/report.md` (written
|
|
20
|
+
// directly by render-report.mjs) is ever meant to be scored.
|
|
21
|
+
//
|
|
22
|
+
// Usage:
|
|
23
|
+
// node create-scratch-dir.mjs [outputDir]
|
|
24
|
+
//
|
|
25
|
+
// Emits the absolute path of the created directory to stdout (a single line,
|
|
26
|
+
// trailing newline). Exit 0 on success, 3 when no candidate base is writable.
|
|
27
|
+
|
|
28
|
+
import { mkdtempSync } from 'node:fs';
|
|
29
|
+
import { join } from 'node:path';
|
|
30
|
+
|
|
31
|
+
const PREFIX = 'itsm-employee-agent.';
|
|
32
|
+
|
|
33
|
+
// Candidate scratch bases, in priority order. `${outputDir}` is LAST so
|
|
34
|
+
// transient captures never enter the scored tree except when no temp dir works.
|
|
35
|
+
const candidates = [];
|
|
36
|
+
const tmp = (process.env.TMPDIR ?? '').trim();
|
|
37
|
+
if (tmp) candidates.push(tmp);
|
|
38
|
+
candidates.push('/tmp');
|
|
39
|
+
const outputDir = (process.argv[2] ?? '').trim();
|
|
40
|
+
if (outputDir) candidates.push(outputDir);
|
|
41
|
+
|
|
42
|
+
let dir = null;
|
|
43
|
+
let lastErr = null;
|
|
44
|
+
for (const base of candidates) {
|
|
45
|
+
try {
|
|
46
|
+
dir = mkdtempSync(join(base, PREFIX));
|
|
47
|
+
break;
|
|
48
|
+
} catch (err) {
|
|
49
|
+
lastErr = err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (dir) {
|
|
54
|
+
process.stdout.write(`${dir}\n`);
|
|
55
|
+
} else {
|
|
56
|
+
process.stderr.write(`error: mkdtemp failed under all of [${candidates.join(', ')}]: ${lastErr?.message ?? 'no base dir'}\n`);
|
|
57
|
+
process.exit(3);
|
|
58
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deterministic renderer for the Employee-agent create/activate report.
|
|
3
|
+
//
|
|
4
|
+
// Composing the report from phase state in model prose is unreliable
|
|
5
|
+
// (authoring standard A9) — the layout, field placement, and next-step
|
|
6
|
+
// wording all belong in a script that emits byte-identical output for a
|
|
7
|
+
// given state input. This helper is the single source of report text for
|
|
8
|
+
// both the chat-turn response and the harness's ${outputDir}/report.md
|
|
9
|
+
// file, so the two never diverge.
|
|
10
|
+
//
|
|
11
|
+
// Usage:
|
|
12
|
+
// node render-report.mjs <state.json> [outPath]
|
|
13
|
+
//
|
|
14
|
+
// state.json shape (all fields optional except `verdict`):
|
|
15
|
+
// {
|
|
16
|
+
// "org": string,
|
|
17
|
+
// "template": { "masterLabel": string, "id": string, "kind": "broad" | "specialized" },
|
|
18
|
+
// "developerName":string,
|
|
19
|
+
// "label": string,
|
|
20
|
+
// "preflight": { "studioHasAccess": "true" | "false" | "cannot-confirm",
|
|
21
|
+
// "templateAgentScriptPresent": "yes" | "no" | "pending" },
|
|
22
|
+
// "enumerate": { "existsBeforeWrite": "yes" | "no" | "pending",
|
|
23
|
+
// "latestVersionStatus": "Active" | "Inactive" | "n/a" | "pending" },
|
|
24
|
+
// "confirmToWrite": "true" | "false" | "pending",
|
|
25
|
+
// "createBundle": string,
|
|
26
|
+
// "publish": string,
|
|
27
|
+
// "activate": string,
|
|
28
|
+
// "verify": string,
|
|
29
|
+
// "verdict": "CREATED" | "ALREADY-CREATED" | "ACTIVATED" |
|
|
30
|
+
// "PENDING CONFIRMATION" | "DECLINED" | "FAILED",
|
|
31
|
+
// "reason": string
|
|
32
|
+
// }
|
|
33
|
+
//
|
|
34
|
+
// If `outPath` is provided, writes to that path; otherwise emits to stdout.
|
|
35
|
+
// The rendered report is always ~30 lines and shape-identical run to run.
|
|
36
|
+
|
|
37
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
38
|
+
|
|
39
|
+
const [statePath, outPath] = process.argv.slice(2);
|
|
40
|
+
if (!statePath) {
|
|
41
|
+
process.stderr.write('usage: node render-report.mjs <state.json> [outPath]\n');
|
|
42
|
+
process.exit(2);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let state;
|
|
46
|
+
try {
|
|
47
|
+
state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
48
|
+
} catch (err) {
|
|
49
|
+
process.stderr.write(`error: could not read/parse ${statePath}: ${err.message}\n`);
|
|
50
|
+
process.exit(3);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const VALID_VERDICTS = new Set([
|
|
54
|
+
'CREATED', 'ALREADY-CREATED', 'ACTIVATED',
|
|
55
|
+
'PENDING CONFIRMATION', 'DECLINED', 'FAILED',
|
|
56
|
+
]);
|
|
57
|
+
const verdict = String(state?.verdict ?? '').trim();
|
|
58
|
+
if (!VALID_VERDICTS.has(verdict)) {
|
|
59
|
+
process.stderr.write(`error: verdict "${verdict}" is not one of: ${[...VALID_VERDICTS].join(', ')}\n`);
|
|
60
|
+
process.exit(3);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function field(v, fallback = 'pending') {
|
|
64
|
+
const s = v === undefined || v === null ? '' : String(v).trim();
|
|
65
|
+
return s === '' ? fallback : s;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const org = field(state.org, '<unspecified>');
|
|
69
|
+
const tmplLabel = field(state?.template?.masterLabel, 'IT Service Employee');
|
|
70
|
+
const tmplId = field(state?.template?.id, 'svc_emp_intelligence__ItEmployeeAssistance');
|
|
71
|
+
const tmplKind = field(state?.template?.kind, 'broad umbrella');
|
|
72
|
+
const devName = field(state.developerName, '<pending>');
|
|
73
|
+
const label = field(state.label, '<pending>');
|
|
74
|
+
|
|
75
|
+
const preStudio = field(state?.preflight?.studioHasAccess, 'pending');
|
|
76
|
+
const preTmpl = field(state?.preflight?.templateAgentScriptPresent, 'pending');
|
|
77
|
+
const enumExists = field(state?.enumerate?.existsBeforeWrite, 'pending');
|
|
78
|
+
const enumVer = field(state?.enumerate?.latestVersionStatus, 'pending');
|
|
79
|
+
|
|
80
|
+
function classifyPreflightVerdict() {
|
|
81
|
+
const explicit = field(state?.preflight?.verdict, '');
|
|
82
|
+
if (explicit !== 'pending' && explicit !== '') return explicit;
|
|
83
|
+
if (preStudio === 'false' || preTmpl === 'no') return 'NOT-READY';
|
|
84
|
+
const okStudio = preStudio === 'true';
|
|
85
|
+
const okTmpl = preTmpl === 'yes';
|
|
86
|
+
if (okStudio && okTmpl) return 'READY';
|
|
87
|
+
if (preStudio === 'cannot-confirm' || preTmpl === 'pending') return 'CANNOT-CONFIRM';
|
|
88
|
+
return 'pending';
|
|
89
|
+
}
|
|
90
|
+
function classifyEnumerate() {
|
|
91
|
+
const explicit = field(state?.enumerate?.verdict, '');
|
|
92
|
+
if (explicit !== 'pending' && explicit !== '') return explicit;
|
|
93
|
+
if (enumExists === 'yes') {
|
|
94
|
+
if (enumVer === 'Active') return 'exists:true, needsActivation:false';
|
|
95
|
+
if (enumVer === 'Inactive') return 'exists:true, needsActivation:true';
|
|
96
|
+
return 'exists:true';
|
|
97
|
+
}
|
|
98
|
+
if (enumExists === 'no') return 'exists:false';
|
|
99
|
+
return 'pending';
|
|
100
|
+
}
|
|
101
|
+
const preVerdict = classifyPreflightVerdict();
|
|
102
|
+
const enumVerdict = classifyEnumerate();
|
|
103
|
+
|
|
104
|
+
const confirm = field(state.confirmToWrite, 'pending');
|
|
105
|
+
const isPending = verdict === 'PENDING CONFIRMATION';
|
|
106
|
+
const isDeclined = verdict === 'DECLINED';
|
|
107
|
+
const isCreated = verdict === 'CREATED';
|
|
108
|
+
const isActivated = verdict === 'ACTIVATED';
|
|
109
|
+
const isAlready = verdict === 'ALREADY-CREATED';
|
|
110
|
+
const isFailed = verdict === 'FAILED';
|
|
111
|
+
const gatedFallback = isPending
|
|
112
|
+
? 'pending confirmation'
|
|
113
|
+
: isDeclined ? 'skipped'
|
|
114
|
+
: isAlready ? 'skipped (already exists)'
|
|
115
|
+
: isFailed ? 'skipped'
|
|
116
|
+
: 'pending';
|
|
117
|
+
|
|
118
|
+
const bundleVersionId = field(state.bundleVersionId, '');
|
|
119
|
+
const bundleVersionIdSuffix = bundleVersionId ? ` bundleVersionId=${bundleVersionId}` : '';
|
|
120
|
+
const onBundleVersionId = bundleVersionId ? ` on bundleVersionId=${bundleVersionId}` : '';
|
|
121
|
+
|
|
122
|
+
function withCreateSuffix(base) {
|
|
123
|
+
if (base === 'pending' || base.startsWith('skipped') || base === 'pending confirmation') return base;
|
|
124
|
+
return `${base}${bundleVersionIdSuffix}`;
|
|
125
|
+
}
|
|
126
|
+
function withPublishActivateSuffix(base) {
|
|
127
|
+
if (base === 'pending' || base.startsWith('skipped') || base === 'pending confirmation') return base;
|
|
128
|
+
return `${base}${onBundleVersionId}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const createBundle = withCreateSuffix(field(state.createBundle, gatedFallback));
|
|
132
|
+
const publish = withPublishActivateSuffix(field(state.publish, gatedFallback));
|
|
133
|
+
const activate = withPublishActivateSuffix(field(state.activate, gatedFallback));
|
|
134
|
+
const verifyFallback = isDeclined || isPending || isFailed
|
|
135
|
+
? 'skipped'
|
|
136
|
+
: isAlready
|
|
137
|
+
? `exists:true; latestVersionStatus=${enumVer}`
|
|
138
|
+
: 'pending';
|
|
139
|
+
let verify = field(state.verify, verifyFallback);
|
|
140
|
+
if (
|
|
141
|
+
(isCreated || isActivated) &&
|
|
142
|
+
verify !== 'pending' &&
|
|
143
|
+
!verify.startsWith('skipped') &&
|
|
144
|
+
!/exists\s*[:=]/i.test(verify)
|
|
145
|
+
) {
|
|
146
|
+
verify = `${verify}; exists:true; latestVersionStatus=Active`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const reason = String(state.reason ?? '').trim();
|
|
150
|
+
|
|
151
|
+
const NEXT_STEPS = {
|
|
152
|
+
'CREATED':
|
|
153
|
+
'The IT Service Employee 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.',
|
|
154
|
+
'ALREADY-CREATED':
|
|
155
|
+
'The IT Service Employee agent was already present and active — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list.',
|
|
156
|
+
'ACTIVATED':
|
|
157
|
+
'The existing IT Service Employee agent was found inactive and has been activated — no new agent was provisioned. Verify end-to-end in Agentforce Studio\'s Agents list.',
|
|
158
|
+
'PENDING CONFIRMATION':
|
|
159
|
+
'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.',
|
|
160
|
+
'DECLINED':
|
|
161
|
+
'No write occurred. This skill\'s create + publish + activate run 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. The user\'s decline (or "hold off on activation") kept the run at the gate. Re-run and confirm when ready for the full sequence.',
|
|
162
|
+
'FAILED':
|
|
163
|
+
reason
|
|
164
|
+
? `Review the Reason above and remediate. Enablement of missing prerequisites is a Setup-UI/admin action outside this skill's scope — use \`service-itsm-agentic-setup-agentforce-studio-validate\` or \`service-itsm-agentic-setup-agentforce-studio-configure\` to check/enable readiness first. Re-run this skill once the blocker is resolved.`
|
|
165
|
+
: 'Review the observed error and remediate. Enablement of missing prerequisites is a Setup-UI/admin action outside this skill\'s scope — use `service-itsm-agentic-setup-agentforce-studio-validate` or `service-itsm-agentic-setup-agentforce-studio-configure` to check/enable readiness first. Re-run this skill once the blocker is resolved.',
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const report = `# Employee Agent — Create & Activate
|
|
169
|
+
|
|
170
|
+
IT Service Employee Agent Creation (via service-itsm-agentic-setup-employee-agent-configure)
|
|
171
|
+
|
|
172
|
+
Org: ${org} (API v67.0)
|
|
173
|
+
Template: ${tmplLabel} (id=${tmplId}) — ${tmplKind}
|
|
174
|
+
Source: ${tmplId} Agent Script
|
|
175
|
+
Agent: ${devName} ("${label}") — NGA-native bundle
|
|
176
|
+
|
|
177
|
+
Preflight ......................... Studio hasAccess=${preStudio}; template agentScript present=${preTmpl}; verdict=${preVerdict}
|
|
178
|
+
Enumerate ......................... target agent exists before write=${enumExists}; latest version status=${enumVer}; verdict=${enumVerdict}
|
|
179
|
+
Confirm-to-write ................... user-confirmed=${confirm}${(confirm === 'true' && (devName !== '<pending>' || label !== '<pending>')) ? `; confirmed developerName=${devName}, label="${label}"` : ''}
|
|
180
|
+
Create bundle ...................... ${createBundle}
|
|
181
|
+
Publish ............................ ${publish}
|
|
182
|
+
Activate ........................... ${activate}
|
|
183
|
+
Verify ............................. ${verify}
|
|
184
|
+
|
|
185
|
+
Verdict: ${verdict}
|
|
186
|
+
Reason: ${reason}
|
|
187
|
+
|
|
188
|
+
Next steps:
|
|
189
|
+
- ${NEXT_STEPS[verdict]}
|
|
190
|
+
`;
|
|
191
|
+
|
|
192
|
+
if (outPath) {
|
|
193
|
+
writeFileSync(outPath, report, 'utf8');
|
|
194
|
+
process.stdout.write(outPath + '\n');
|
|
195
|
+
} else {
|
|
196
|
+
process.stdout.write(report);
|
|
197
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-itsm-agentic-setup-fulfiller-agent-configure
|
|
3
|
+
description: "Create and activate the IT Service Fulfiller agent as a Next-Gen Authoring (NGA) native agent from the shipped ITSM Fulfiller template's Agent Script, using the Salesforce CLI (sf): read the template, check idempotency, create the NGA bundle then publish and activate it, then verify it is live. Idempotent per developer name. The Fulfiller agent is the IT-technician-facing assistant for incident triage, case summarization, field updates, and related-record automations. Use when asked to create the Fulfiller agent, set up the IT Service Fulfiller agent, provision the fulfiller assistant, or activate the Fulfiller agent. Triggers: create fulfiller agent, set up fulfiller agent, provision fulfiller agent, activate fulfiller agent. DO NOT TRIGGER: checking org prerequisites (service-itsm-agentic-setup-agentforce-studio-validate), or CMDB CRUD."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "3.3"
|
|
6
|
+
domains: ["Service", "Agentforce"]
|
|
7
|
+
minApiVersion: "67.0"
|
|
8
|
+
relatedSkills:
|
|
9
|
+
- "service-itsm-agentic-setup-agentforce-studio-configure"
|
|
10
|
+
- "service-itsm-agentic-setup-agentforce-studio-validate"
|
|
11
|
+
- "service-itsm-agentic-setup-employee-agent-configure"
|
|
12
|
+
- "service-itsm-agentic-setup-itsm-agentforce-permset-assign"
|
|
13
|
+
cliTools:
|
|
14
|
+
- tool: ["node"]
|
|
15
|
+
semver: ">=18.0.0"
|
|
16
|
+
- tool: ["sf"]
|
|
17
|
+
semver: ">=2.0.0"
|
|
18
|
+
accessCheck:
|
|
19
|
+
- type: "license"
|
|
20
|
+
value: "Agentforce"
|
|
21
|
+
allowed-tools: |
|
|
22
|
+
Bash
|
|
23
|
+
Read
|
|
24
|
+
Write
|
|
25
|
+
AskUserQuestion
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Create the IT Service Fulfiller Agent
|
|
29
|
+
|
|
30
|
+
Create and activate the **IT Service Fulfiller Agent** as a **Next-Gen Authoring (NGA) native agent** — Agent-Script-based (`AiAuthoringBundleDefVer`/bundle), appearing natively in Agentforce Studio's Agents list with no external-link icon — entirely through the **Salesforce CLI (`sf`)**. **This skill does not call the legacy `/connect/service-itsm/createAgent`**; instead it reuses the shipped ITSM Fulfiller template's `agentScript` and feeds it into the NGA bundle pipeline:
|
|
31
|
+
|
|
32
|
+
1. `POST /nextgen-authoring/bundles` (`createBundleWithVersion`) — creates the bundle + first version from the template's Agent Script.
|
|
33
|
+
2. `POST /nextgen-authoring/bundle-versions/{id}/publish` — publishes the version (creates the underlying `BotDefinition`/`BotVersion`).
|
|
34
|
+
3. `POST /nextgen-authoring/bundle-versions/{id}/activate` — activates it.
|
|
35
|
+
|
|
36
|
+
Commands: `sf api request rest` for Connect API GET/POST; `sf data query` for the SOQL idempotency + verify reads.
|
|
37
|
+
|
|
38
|
+
Helper scripts (invoked via `Bash`) hold every JSON-parsing / decision rule so the model never eyeballs a response body (A9): `classify-preflight.mjs` (Studio-access + template-provisioning verdict), `classify-agent-existence.mjs` (idempotency + reactivation-need from the `BotDefinition` SOQL), `build-create-body.mjs` (HTML-decodes and substitutes the template's `agentScript`, writes the bundle-create body to a JSON file so large content and free-text quotes never hit an inline shell string), `render-report.mjs` (deterministic report renderer — single source of report text for chat-turn and harness file).
|
|
39
|
+
|
|
40
|
+
The Fulfiller agent is the **IT-technician-facing assistant** — incident triage, case summarization, field updates, related-record automations. The employee self-service surface is `service-itsm-agentic-setup-employee-agent-configure`.
|
|
41
|
+
|
|
42
|
+
## Scope
|
|
43
|
+
|
|
44
|
+
- **In scope**: Reading `agent-templates`; extracting the Fulfiller template's Agent Script (`svc_itsm_intelligence__ITSrvcMgmtFulfiller`); creating the Fulfiller agent as an **NGA-native agent** via `createBundleWithVersion` → `publish` → `activate`; SOQL-verifying live; idempotent skip on duplicate developer name — all via `sf`.
|
|
45
|
+
- **Out of scope**: The Employee agent — broad or ~47 specializations under `svc_emp_intelligence__` (`service-itsm-agentic-setup-employee-agent-configure`); enabling org-level feature toggles (validated by `service-itsm-agentic-setup-agentforce-studio-validate`); low-level topic/action authoring; perm-set assignment; content-bundle deployment; CMDB CRUD; Discovery / Service Graph; the legacy `createAgent` route.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Preconditions
|
|
50
|
+
|
|
51
|
+
If any of these are unmet, `sf` surfaces an auth error or a `401`/`403`/`404`; **surface the raw error verbatim and stop — do not fabricate state**.
|
|
52
|
+
|
|
53
|
+
1. **`sf` CLI authenticated** to the target org (`sf org display -o <alias>` shows Connected). All calls use `--target-org <alias>`; never extract the access token by hand.
|
|
54
|
+
2. **API v67.0+** — pinned in the URL path; do not hand-edit below the minimum.
|
|
55
|
+
3. **ITSM features + Fulfiller template provisioned** (`svc_itsm_intelligence__ITSrvcMgmtFulfiller`). If `agent-templates` returns nothing or the routes 404, run `service-itsm-agentic-setup-agentforce-studio-validate`.
|
|
56
|
+
4. **`node` ≥ 18** on PATH.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Operations at a glance
|
|
61
|
+
|
|
62
|
+
| Concern | Command | Notes |
|
|
63
|
+
|---------|---------|-------|
|
|
64
|
+
| Studio access (precondition read) | `sf api request rest "/services/data/v67.0/agentforce-studio/access/Agents" --method GET -o <alias>` | `hasAccess=false` ⇒ prereq hand-off |
|
|
65
|
+
| List agent templates + Agent Script (read) | `sf api request rest "/services/data/v67.0/connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent" --method GET -o <alias>` | `agentType=AgentforceEmployeeAgent` required; confirms Fulfiller template + non-empty `agentScript` |
|
|
66
|
+
| Enumerate the existing agent + latest version status (read) | `sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'" -o <alias> --json` | Keyed PRIMARILY on the template's `botDefinitionId` (Phase-1 row); the `OR DeveloperName=` clause is both the null-`botDefinitionId` fallback (the normal Fulfiller case) AND the guard for a dangling Id link (deleted target). Classified by `scripts/classify-agent-existence.mjs`; Active latest ⇒ ALREADY-CREATED; Inactive latest ⇒ offer reactivation |
|
|
67
|
+
| **Create the NGA bundle** (write) | `sf api request rest "/services/data/v67.0/nextgen-authoring/bundles" --method POST --body @<body-file> -o <alias>` | Body built by `scripts/build-create-body.mjs`; response `id` = the bundle **version** Id |
|
|
68
|
+
| **Publish the bundle version** (write) | `sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/publish" --method POST --body '{}' -o <alias>` | Returns `publishedBotId`/`publishedBotVersionId` — creates the underlying `BotDefinition`/`BotVersion` |
|
|
69
|
+
| **Activate the bundle version** (write) | `sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/activate" --method POST --body '{}' -o <alias>` | Empty response on success; agent is now live and NGA-native |
|
|
70
|
+
| **Activate an existing inactive version** (write) | `sf api request rest "/services/data/v67.0/connect/bot-versions/<latestVersionId>/activation" --method POST --body '{"status":"Active"}' -o <alias>` | Reactivation path only (Phase 2b) — skips create/publish |
|
|
71
|
+
| Verify agent is live (read) | `sf data query -q "SELECT ... FROM BotDefinition WHERE Id='<verifyId>'" -o <alias> --json` | `<verifyId>` = create path's `publishedBotId` (Phase-5) or the Phase-2 classifier's returned live matched Id (its `botDefinitionId`/`agentId`) on ALREADY-CREATED / reactivation — not the null Phase-1 template `botDefinitionId`, never the collected developerName; confirm `BotDefinition` present + latest version Active |
|
|
72
|
+
|
|
73
|
+
Full command shapes and the ITSM Connect API reference live in `references/cli-invocation.md`; the reactivation-path call + idempotency verdict table live in `references/reactivation.md`; the response-body error codes and recurring gotchas live in `references/error-taxonomy.md`.
|
|
74
|
+
|
|
75
|
+
> **Never extract the access token.** Use `sf api request rest` / `sf data query` directly — they use the CLI's stored session for the target org. Do **not** pull the `accessToken` out of `sf org display` and hand-build an HTTP request with it; that bypasses the CLI session and leaks a bearer token into shell context.
|
|
76
|
+
|
|
77
|
+
> **`--json` rule.** `sf data query` **takes** `--json` (results come back in a `.result.records[]` envelope — that's what the classifier expects). `sf api request rest` does **not** — omit `--json` there; its raw stdout body is already JSON.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Shipped ITSM Fulfiller agent template
|
|
82
|
+
|
|
83
|
+
| Template identifier | Default developer name |
|
|
84
|
+
|---------------------|-------------------------|
|
|
85
|
+
| `svc_itsm_intelligence__ITSrvcMgmtFulfiller` (`masterLabel` "IT Service Fulfiller") | `IT_Service_Fulfiller_Agent` |
|
|
86
|
+
|
|
87
|
+
> **The `agentScript` field is the source of truth for the NGA create — not `id`.** `scripts/build-create-body.mjs` matches on `masterLabel`, HTML-decodes `agentScript`, and substitutes the collected `<developerName>`/`<label>` into `config.developer_name`/`config.agent_label` before it becomes the bundle's `resourceContent`. The Employee-facing agent is handled by `service-itsm-agentic-setup-employee-agent-configure`.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Architecture — Creation stages
|
|
92
|
+
|
|
93
|
+
| Stage | What happens | Tool used |
|
|
94
|
+
|-------|--------------|-----------|
|
|
95
|
+
| Preflight | Confirm Studio access (`agentforce-studio/access/Agents`) and that the template's `agentScript` is present | `Bash` (`sf api request rest`) |
|
|
96
|
+
| Enumerate | Read the Fulfiller template (`agent-templates`) and existing agents + latest version status (SOQL on `BotDefinition`/`BotVersions`); classify idempotency and reactivation-need via script | `Bash` (`sf`, `node`) |
|
|
97
|
+
| Confirm-to-write | Present the exact developerName + label (the NGA create target), OR — if the existing agent is inactive — present the reactivation option instead, and require explicit "yes" either way | `AskUserQuestion` |
|
|
98
|
+
| Create *(create path only)* | POST `createBundleWithVersion` (builds the NGA bundle + first version from the decoded, substituted template Agent Script) | `Bash` (`sf api request rest`, `node`) |
|
|
99
|
+
| Publish *(create path only)* | POST `.../bundle-versions/<id>/publish` (creates the underlying `BotDefinition`/`BotVersion`) | `Bash` (`sf api request rest`) |
|
|
100
|
+
| Activate | POST `.../bundle-versions/<id>/activate` (create path) OR POST `.../connect/bot-versions/<latestVersionId>/activation` with `{"status":"Active"}` (reactivation path — skips create/publish) | `Bash` (`sf api request rest`) |
|
|
101
|
+
| Verify | SOQL-read `BotDefinition`/`BotVersions` and confirm the agent exists with an Active latest version | `Bash` (`sf data query`) |
|
|
102
|
+
|
|
103
|
+
**Idempotency**: keyed PRIMARILY on the **template's `botDefinitionId`** (Phase-1 `agent-templates` row — the platform's authoritative template→`BotDefinition` link) and FALLING BACK to the collected `<developerName>`. The Phase-2 read is `BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'` (the `OR` half is both the null-`botDefinitionId` fallback — the normal Fulfiller case — AND the guard for a **dangling** Id link whose target `BotDefinition` was deleted, so a stale link can't slip through to create), + latest `BotVersion.Status` (classified by the helper script). Outcomes: no match on either key ⇒ `exists:false` ⇒ create; `latestVersionStatus:"Active"` ⇒ **ALREADY-CREATED** (skip the write, fall through to Phase 7 verification); `needsActivation:true` (latest version `Inactive`) ⇒ **offer to activate the existing version instead of creating a new agent** (Phase 2b) rather than silently skipping or duplicating. **Why the fallback matters:** the Fulfiller is never pre-provisioned and this skill's create path never stamps `templateName`, so the template's `botDefinitionId` is always `null` — the `<developerName>`-keyed fallback is the guard that actually catches a repeat run; short-circuiting straight to create on a null `botDefinitionId` would re-create and collide with `DUPLICATE_VALUE`. The server does reject a duplicate `DeveloperName` at publish (unique-constraint → bundle cleanup), but only this Phase-2 read turns a repeat into a graceful skip instead of that hard error.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Clarifying Questions
|
|
108
|
+
|
|
109
|
+
Collect from the user (ask only what is not already in conversation context):
|
|
110
|
+
|
|
111
|
+
| Field | Description | Default |
|
|
112
|
+
|-------|-------------|---------|
|
|
113
|
+
| Target org | The `sf` org alias to create the agent in | Default org (`sf config get target-org`) |
|
|
114
|
+
| Developer name | Unique `DeveloperName` for the agent | `IT_Service_Fulfiller_Agent` |
|
|
115
|
+
| Label | User-facing label for the agent | `IT Service Fulfiller Agent` |
|
|
116
|
+
| Confirm the write | Explicit confirmation before the create/publish/activate sequence | **REQUIRED** — present the developerName + label and require "yes" via `AskUserQuestion` |
|
|
117
|
+
|
|
118
|
+
The **idempotency read keys PRIMARILY on the template's `botDefinitionId`** (Phase-1 row) and FALLS BACK to the collected `<developerName>` when that is null; the verify read keys on the publish response's `publishedBotId` (create path) or the template's `botDefinitionId` (ALREADY-CREATED / reactivation). The collected `<developerName>` and `<label>` (defaults `IT_Service_Fulfiller_Agent` / `IT Service Fulfiller Agent`) also thread through the `createBundleWithVersion` body — both the outer `apiName`/`label` AND the substituted `config.developer_name`/`config.agent_label` inside the Agent Script. Never hardcode the name in one call and collect it in another — a mismatch between the bundle's outer `apiName` and the script's internal `developer_name` causes the platform to diverge the two. Creating an agent provisions a live, activated agent on the org; the user must explicitly approve the write.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Workflow
|
|
123
|
+
|
|
124
|
+
Substitute `<alias>` with the collected target org and `<developerName>` / `<label>` with the collected values. Full command shapes + per-phase verdict-branch handling live in `references/workflow-detail.md` — the phase summary below names each step and its load-bearing rule; the reference file holds the exact `sf` / `node` invocations to copy.
|
|
125
|
+
|
|
126
|
+
0. **Phase 0 — Establish `${SCRATCH_DIR}`.** Invoke the deterministic helper (path is skill-root-qualified so it resolves regardless of the shell's CWD): `SCRATCH_DIR="$(node "<skill_dir>/scripts/create-scratch-dir.mjs" "${outputDir:-}")"`. Helper picks the base dir (`${TMPDIR}`, else `/tmp`, else the harness `${outputDir}` last-resort — scratch stays OUT of the scored `${outputDir}` tree) and emits the created dir on stdout. All transient JSON lands under `${SCRATCH_DIR}`; the durable `${outputDir}/report.md` stays under the harness dir.
|
|
127
|
+
1. **Phase 1 — Preflight.** Capture the Studio-access read + `agent-templates` read (with the **required** `agentType=AgentforceEmployeeAgent` query param) into `${SCRATCH_DIR}/agent-templates.json`, then classify via `scripts/classify-preflight.mjs "IT Service Fulfiller"`. The classifier also emits `template.botDefinitionId` from the matched row — **capture it; it is the primary Phase-2 idempotency key (the collected `<developerName>` is the fallback key).** Branch on `verdict`: `READY` ⇒ Phase 2; `NOT-READY` ⇒ prerequisite hand-off via `AskUserQuestion` (delegate to `service-itsm-agentic-setup-agentforce-studio-validate` on "yes"); `ERROR` ⇒ surface + stop; `studio.signal="CANNOT-CONFIRM"` (confirmed 404) does not block.
|
|
128
|
+
2. **Phase 2 — Idempotency (primary key `botDefinitionId`, fallback key `<developerName>`).** Take `template.botDefinitionId` from Phase 1. **Present** ⇒ SOQL `BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'` with the `BotVersions` subquery (subquery is required — otherwise `needsActivation` is permanently false; the `OR` clause makes a **dangling** Id link — deleted target — fall back to the live same-name agent instead of a false `exists:false` → duplicate create). **Empty/null** (the normal Fulfiller case — the template row is never back-filled) ⇒ do NOT skip to create; fall back to `BotDefinition WHERE DeveloperName='<developerName>'` (a self-created agent from a prior run has a null template `botDefinitionId` but still exists). Either way classify via `scripts/classify-agent-existence.mjs ${SCRATCH_DIR}/bot-existing.json "<botDefinitionId-or-empty>" "<developerName>"`. Branch: `exists:false` ⇒ **Phase 2c** (action-availability gate, then create); `exists:true` + `needsActivation:false` ⇒ **ALREADY-CREATED** (skip straight to Phase 7 — no action-availability gate; a live active agent's actions are already wired); `exists:true` + `needsActivation:true` ⇒ Phase 2b. Non-zero exit ⇒ surface CLI error; never assume absent. **Why the fallback:** the Fulfiller is never pre-provisioned, so `botDefinitionId` is always null — a missing developerName check would re-create and hit `DUPLICATE_VALUE`.
|
|
129
|
+
3. **Phase 2b — Reactivation offer.** `AskUserQuestion`: _"Fulfiller agent `<developerName>` exists but latest version is Inactive. Activate it?"_. On **Yes**: `POST /connect/bot-versions/<latestVersionId>/activation` with `{"status":"Active"}` captured to `${SCRATCH_DIR}/activate-response.json`, then `node "<skill_dir>/scripts/classify-activate-result.mjs" ${SCRATCH_DIR}/activate-response.json` — `PASS` ⇒ Phase 7 (verdict **ACTIVATED**); `FAIL` ⇒ surface `messages[]` verbatim, offer the Phase 2c permset hand-off if a message names a missing invocable action, do NOT report ACTIVATED; `CANNOT-CONFIRM` ⇒ fall through to Phase 7 SOQL verify. On **No**: stop, no writes.
|
|
130
|
+
4. **Phase 2c — Action-availability preflight (create path only; reached only from Phase 2 `exists:false`).** Capture `sf api request rest "/services/data/v67.0/actions/custom/generatePromptResponse" --method GET` to `${SCRATCH_DIR}/generate-prompt-response.json`, then `node "<skill_dir>/scripts/classify-action-availability.mjs" ${SCRATCH_DIR}/agent-templates.json "IT Service Fulfiller" ${SCRATCH_DIR}/generate-prompt-response.json`. Branch on `verdict`: `READY` ⇒ Phase 3; `NOT-READY` ⇒ `AskUserQuestion` offering hand-off to `service-itsm-agentic-setup-itsm-agentforce-permset-assign` (surface `missing[]` verbatim — do NOT proceed to write; the activate call would return HTTP 200 with a `{success:false}` silent-failure body); `CANNOT-CONFIRM` ⇒ surface reasons and proceed with caution (Phase 6 activate-result classifier catches the silent-failure body). Full contract in `references/action-availability.md`.
|
|
131
|
+
5. **Phase 3 — Confirm-to-Write (REQUIRED, create path only).** If `${outputDir}` was provided, first render the checkpoint file via `render-report.mjs` with `verdict:"PENDING CONFIRMATION"` (skip for interactive runs). THEN raise the `AskUserQuestion` gate presenting developerName + label + "NGA-native from the Fulfiller template's Agent Script". Proceed **only** on explicit "yes"; on "no", re-render with `verdict:"DECLINED"`.
|
|
132
|
+
6. **Phase 4 — Create.** `scripts/build-create-body.mjs ${SCRATCH_DIR}/agent-templates.json "IT Service Fulfiller" "<developerName>" "<label>" ${SCRATCH_DIR}/create-bundle-body.json` (helper re-reads Phase-1 templates JSON, HTML-decodes the matched `agentScript`, substitutes internal `config.developer_name`/`config.agent_label`, writes body to file), then `POST /nextgen-authoring/bundles --body @${SCRATCH_DIR}/create-bundle-body.json`. **Capture response `id`** — that is the `bundleVersionId` for Phases 5–6, not `bundleId`. `403 FUNCTIONALITY_NOT_ENABLED`/`404` ⇒ trigger the Phase-1 hand-off; build-script exit 3 ⇒ surface stderr.
|
|
133
|
+
7. **Phase 5 — Publish.** `POST /nextgen-authoring/bundle-versions/<bundleVersionId>/publish --body '{}'` (empty body required). Success: `{ lastPublishedOn, publishedBotId, publishedBotVersionId }` — this call creates the underlying `BotDefinition`/`BotVersion`. Any error ⇒ surface verbatim; never activate an unpublished version.
|
|
134
|
+
8. **Phase 6 — Activate.** `POST /nextgen-authoring/bundle-versions/<bundleVersionId>/activate --body '{}'` captured to `${SCRATCH_DIR}/activate-response.json`, then `node "<skill_dir>/scripts/classify-activate-result.mjs" ${SCRATCH_DIR}/activate-response.json` — activate can return HTTP 200 with a `{success:false}` silent-failure body when a referenced invocable action isn't surfaced; the classifier catches that. `PASS` ⇒ Phase 7; `FAIL` ⇒ surface `messages[]`, offer Phase 2c permset hand-off if a message names a missing action, do NOT report CREATED; `CANNOT-CONFIRM` ⇒ fall through to Phase 7 SOQL verify.
|
|
135
|
+
9. **Phase 7 — Verify.** SOQL `BotDefinition WHERE Id='<id>'` (+ `BotVersions` subquery) and classify — `<id>` is the create path's `publishedBotId` (captured from Phase 5) or, on the ALREADY-CREATED / reactivation path, the **live matched Id the Phase-2 classifier returned** (its `botDefinitionId`/`agentId` output — the actual `BotDefinition.Id` of the matched record), **not** the Phase-1 template `botDefinitionId` (which is always null for the Fulfiller, so on any existing-agent hit the verify would run `WHERE Id=''` and falsely report failure after a successful skip/activation). Confirm `exists:true, count:1, latestVersionStatus:"Active"`. Any discrepancy ⇒ report verbatim, do not fabricate success.
|
|
136
|
+
10. **Phase 8 — Aggregate verdict.** Emit CREATED / ALREADY-CREATED / ACTIVATED / FAILED (ACTIVATED on the Phase-2b path) + `BotDefinition` Id / bundle `id` by re-invoking `render-report.mjs` — the single source of report text. If `${outputDir}` was provided, overwrite `${outputDir}/report.md`; otherwise emit stdout as the turn-side report.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Rules / Constraints
|
|
141
|
+
|
|
142
|
+
| Constraint | Rationale |
|
|
143
|
+
|-----------|-----------|
|
|
144
|
+
| All calls go through `sf api request rest` / `sf data query`; **never extract the access token** | Leaks a bearer token into shell context; the CLI's stored session is the correct surface |
|
|
145
|
+
| Idempotency read keys PRIMARILY on the template's `botDefinitionId` (Phase-1 row), falling back to the collected `<developerName>` when null; the verify read keys on the publish `publishedBotId` / `botDefinitionId`; that same `<developerName>`/`<label>` also thread through the create body (outer `apiName`/`label` AND the substituted `config.developer_name`/`config.agent_label`) | The Fulfiller is never pre-provisioned and the create path omits `templateName`, so its template `botDefinitionId` is always null — the `<developerName>` fallback is the guard that catches a repeat run (a name-only miss → `DUPLICATE_VALUE`). A create-body hardcode/collect mismatch diverges the bundle's outer identity from the script's internal identity |
|
|
146
|
+
| Preflight, idempotency, bundle-body construction, and report rendering all live in `scripts/*.mjs`, not prose (A9) | JSON parsing + `masterLabel` matching + `hasAccess` reads + verdict emission are deterministic; the ~70KB Agent Script and free-text apostrophes cannot be safely interpolated into a shell string — `JSON.stringify` in the helper escapes them |
|
|
147
|
+
| Three-call sequence: `createBundleWithVersion` → `publish` → `activate`, in that order, on the SAME captured `bundleVersionId` (response `id`, not `bundleId`) | Platform enforces DRAFT → published → active; response-body / empty-body / `--json` / `agentType` / HTML-decode gotchas live in `references/error-taxonomy.md` |
|
|
148
|
+
| Enumerate `BotDefinition` **with the `BotVersions` subquery**; skip create when Active; offer Phase-2b reactivation when Inactive — never silent skip, never duplicate create | Subquery is what distinguishes Active/Inactive; the server rejects a duplicate `DeveloperName` at publish (unique-constraint → bundle cleanup), so this read is what turns a repeat into a graceful skip instead of that hard error |
|
|
149
|
+
| **REQUIRED confirm-to-write checkpoint** before create sequence or reactivation call | Both change live org state — explicit user approval required |
|
|
150
|
+
| On `hasAccess=false` / `403 FUNCTIONALITY_NOT_ENABLED`, offer the readiness hand-off — never enable features here; never call legacy `/connect/service-itsm/createAgent` | Enablement is a Setup-UI/admin action; `createAgent` produces a Setup-page bot with an external-link icon (wrong kind of agent for this skill) |
|
|
151
|
+
| Report exact CLI response text on any error | Enables support to diagnose failures |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Verification Checklist
|
|
156
|
+
|
|
157
|
+
- [ ] Preflight classified by `classify-preflight.mjs` (PASS or documented CANNOT-CONFIRM); hand-off offered on FAIL; raw error surfaced on ERROR.
|
|
158
|
+
- [ ] Idempotency keyed on the template's `botDefinitionId` (Phase-1 row) with the collected developerName as fallback; `BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'` (the `OR` covers both a null and a dangling `botDefinitionId`) + latest `BotVersion.Status` (subquery present) read + classified before any write.
|
|
159
|
+
- [ ] If `needsActivation:true`, Phase-2b reactivation offer presented — no silent skip, no duplicate create.
|
|
160
|
+
- [ ] Explicit user confirmation at Phase 3 (create) or Phase 2b (reactivation) before any write.
|
|
161
|
+
- [ ] Bundle body built by `build-create-body.mjs`, POSTed via `--body @<file>` with the collected `developerName`/`label`; or write correctly skipped.
|
|
162
|
+
- [ ] Same `bundleVersionId` (response `id`) used for publish + activate; reactivation used `POST /connect/bot-versions/<id>/activation`; legacy `createAgent` never called.
|
|
163
|
+
- [ ] Phase-7 verify confirmed `BotDefinition` present + latest version Active.
|
|
164
|
+
- [ ] Access token never extracted; final verdict + `BotDefinition`/bundle Id reported.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Output Format
|
|
169
|
+
|
|
170
|
+
The report layout is generated deterministically by `scripts/render-report.mjs` — the single source of report text for both the chat turn and the harness's `${outputDir}/report.md`. Never hand-compose the layout in prose (A9); always shell out to the helper. Full rendered shape, report-state JSON schema, and checkpoint-write rules live in `references/report-format.md`.
|
|
171
|
+
|
|
172
|
+
Terminal verdicts: `CREATED | ALREADY-CREATED | ACTIVATED | PENDING CONFIRMATION | DECLINED | FAILED`. When `${outputDir}` is set, write at Phase 3, Phase 6 (or Phase 2b), and Phase 8 — each write overwrites the same file. Skip these writes in interactive/chat surfaces.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Reference File Index
|
|
177
|
+
|
|
178
|
+
| File | When to read |
|
|
179
|
+
|------|--------------|
|
|
180
|
+
| `references/workflow-detail.md` | Full per-phase verdict-branch narrative that the SKILL body summarizes (Phase-1 ERROR/NOT-READY/CANNOT-CONFIRM, Phase-2 classifier output, Phase-4 create response, error branches) |
|
|
181
|
+
| `references/report-format.md` | Every `render-report.mjs` call — the rendered shape and the three-checkpoint write policy for `${outputDir}/report.md` |
|
|
182
|
+
| `references/cli-invocation.md` | Every phase — exact `sf` call shapes, the never-extract-token rule, ITSM Connect API reference, three helper-script contracts |
|
|
183
|
+
| `references/action-availability.md` | Phase 2c (action-availability preflight, create path) + Phase 2b/6 (activate-result classifier) — silent-failure body catches, permset hand-off wording |
|
|
184
|
+
| `references/reactivation.md` | Reactivation path (`needsActivation:true`) — the direct `POST /connect/bot-versions/{id}/activation` call + full idempotency verdict table |
|
|
185
|
+
| `references/error-taxonomy.md` | Any non-2xx response, unexpected empty body, or script non-zero exit — response-body error codes and recurring foot-guns |
|
|
186
|
+
| `scripts/render-report.mjs` | Every checkpoint that writes `${outputDir}/report.md` (Phase-3 gate, Phase-6 create-succeeded, Phase-8 final) — deterministic renderer from a phase-state JSON |
|