@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.
Files changed (136) hide show
  1. package/package.json +1 -1
  2. package/skills/automation-flow-generate/SKILL.md +32 -43
  3. package/skills/experience-portal-create/SKILL.md +497 -0
  4. package/skills/experience-portal-create/assets/report-template.md +30 -0
  5. package/skills/experience-portal-create/references/mcp-invocation.md +288 -0
  6. package/skills/experience-portal-create/references/post-creation-activate-publish.md +165 -0
  7. package/skills/experience-portal-create/references/templates.md +253 -0
  8. package/skills/experience-ui-bundle-features-generate/SKILL.md +5 -1
  9. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -0
  10. package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -0
  11. package/skills/platform-datamask-run/SKILL.md +345 -0
  12. package/skills/platform-datamask-run/references/api-surface.md +130 -0
  13. package/skills/platform-datamask-run/references/policy-authoring.md +185 -0
  14. package/skills/platform-datamask-run/references/run-and-abort.md +116 -0
  15. package/skills/platform-datamask-run/scripts/poll-job.sh +115 -0
  16. package/skills/platform-dataspace-access-configure/SKILL.md +51 -3
  17. package/skills/platform-dataspace-access-configure/scripts/inspect-dataspace-scopes.sh +56 -0
  18. package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +1 -0
  19. package/skills/platform-sandbox-configure/SKILL.md +17 -2
  20. package/skills/platform-trial-org-create/SKILL.md +175 -0
  21. package/skills/platform-trial-org-create/examples/create_request.json +9 -0
  22. package/skills/platform-trial-org-create/examples/error_response.json +41 -0
  23. package/skills/platform-trial-org-create/examples/success_response.json +27 -0
  24. package/skills/platform-trial-org-create/references/error_codes.md +42 -0
  25. package/skills/platform-trial-org-create/references/signup_request_fields.md +69 -0
  26. package/skills/platform-trial-org-create/scripts/create_signup_request.sh +175 -0
  27. package/skills/platform-trial-org-create/scripts/get_signup_request.sh +155 -0
  28. package/skills/platform-widget-generate/SKILL.md +47 -6
  29. package/skills/platform-widget-generate/examples/conditional.json +3 -3
  30. package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
  31. package/skills/platform-widget-generate/examples/single-object.json +2 -2
  32. package/skills/platform-widget-generate/references/widget-bundle-layout.md +1 -1
  33. package/skills/service-agentforce-channel-configure/SKILL.md +271 -0
  34. package/skills/service-agentforce-channel-configure/references/agent-wiring.md +97 -0
  35. package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +145 -0
  36. package/skills/service-agentforce-channel-configure/references/channel-branch-voice.md +69 -0
  37. package/skills/service-agentforce-channel-configure/references/channel-types.md +61 -0
  38. package/skills/service-agentforce-channel-configure/references/live-traffic-gate.md +86 -0
  39. package/skills/service-agentforce-channel-configure/references/queue-resolution.md +135 -0
  40. package/skills/service-agentforce-channel-configure/references/routing-flow.md +384 -0
  41. package/skills/service-catalog-template-deploy/SKILL.md +310 -0
  42. package/skills/service-catalog-template-deploy/references/cli-invocation.md +258 -0
  43. package/skills/service-catalog-template-deploy/scripts/activate-verify.mjs +164 -0
  44. package/skills/service-catalog-template-deploy/scripts/build-deploy-payload.mjs +94 -0
  45. package/skills/service-catalog-template-deploy/scripts/resolve-template.mjs +331 -0
  46. package/skills/service-catalog-template-search/SKILL.md +212 -0
  47. package/skills/service-catalog-template-search/references/cli-invocation.md +128 -0
  48. package/skills/service-catalog-template-search/scripts/classify-catalog.mjs +205 -0
  49. package/skills/service-concierge-portal-generate/SKILL.md +126 -0
  50. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1428 -0
  51. package/skills/service-digital-engagement-channel-configure/SKILL.md +46 -6
  52. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +2 -1
  53. package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -1
  54. package/skills/service-helpagent-coordinate/README.md +8 -2
  55. package/skills/service-helpagent-coordinate/SKILL.md +126 -130
  56. package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +70 -53
  57. package/skills/service-helpagent-coordinate/references/agent-script.md +571 -457
  58. package/skills/service-helpagent-coordinate/references/channel-voice.md +38 -9
  59. package/skills/service-helpagent-coordinate/references/channel-web-chat.md +173 -49
  60. package/skills/service-helpagent-coordinate/references/output-report-format.md +126 -0
  61. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +153 -0
  62. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +79 -0
  63. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +35 -0
  64. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +271 -0
  65. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +265 -0
  66. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +220 -0
  67. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-final-report.mjs +102 -0
  68. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/record-enable-result.mjs +73 -0
  69. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +206 -0
  70. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +194 -0
  71. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +223 -0
  72. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +45 -7
  73. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +45 -5
  74. package/skills/service-itsm-agentic-setup-configure/SKILL.md +116 -0
  75. package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +64 -0
  76. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +158 -0
  77. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/cli-invocation.md +361 -0
  78. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/error-taxonomy.md +44 -0
  79. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/reactivation.md +66 -0
  80. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +66 -0
  81. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/specialized-templates.md +148 -0
  82. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +169 -0
  83. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/build-create-body.mjs +116 -0
  84. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-agent-existence.mjs +185 -0
  85. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/classify-preflight.mjs +168 -0
  86. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  87. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +197 -0
  88. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +186 -0
  89. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +51 -0
  90. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/cli-invocation.md +345 -0
  91. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/error-taxonomy.md +44 -0
  92. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/reactivation.md +63 -0
  93. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +44 -0
  94. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +149 -0
  95. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +110 -0
  96. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +201 -0
  97. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-activate-result.mjs +135 -0
  98. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-agent-existence.mjs +194 -0
  99. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-preflight.mjs +158 -0
  100. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/create-scratch-dir.mjs +58 -0
  101. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +191 -0
  102. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +133 -0
  103. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +71 -0
  104. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +308 -0
  105. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +23 -0
  106. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +193 -0
  107. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +57 -0
  108. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +394 -0
  109. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +266 -0
  110. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +106 -0
  111. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +142 -0
  112. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +82 -0
  113. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-action-surface.mjs +137 -0
  114. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-assignment-state.mjs +99 -0
  115. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +120 -0
  116. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/resolve-target-user.mjs +86 -0
  117. package/skills/service-itsm-agentic-setup-uel-user-create/SKILL.md +284 -0
  118. package/skills/service-itsm-agentic-setup-uel-user-create/references/mcp-invocation.md +302 -0
  119. package/skills/service-itsm-channels-coordinate/SKILL.md +472 -0
  120. package/skills/service-itsm-incident-mgmt-configure/SKILL.md +212 -0
  121. package/skills/service-itsm-incident-mgmt-configure/references/mcp-invocation.md +225 -0
  122. package/skills/service-itsm-incident-priority-configure/SKILL.md +53 -12
  123. package/skills/service-itsm-swarming-configure/SKILL.md +212 -0
  124. package/skills/service-itsm-teams-configure/SKILL.md +395 -0
  125. package/skills/service-itsm-teams-configure/references/azure-credential-population.md +213 -0
  126. package/skills/service-itsm-teams-configure/references/gotchas.md +23 -0
  127. package/skills/service-itsm-teams-coordinate/SKILL.md +175 -0
  128. package/skills/service-itsm-teams-coordinate/examples/output-templates.md +85 -0
  129. package/skills/service-itsm-teams-debug/SKILL.md +144 -0
  130. package/skills/service-itsm-teams-debug/references/configuration-checklists.md +277 -0
  131. package/skills/service-itsm-teams-debug/references/report-generation.md +95 -0
  132. package/skills/service-itsm-teams-employee-agent-configure/SKILL.md +139 -0
  133. package/skills/service-itsm-teams-employee-agent-configure/assets/Teams_AgentForce.EmbeddedServiceConfig-meta.xml +43 -0
  134. package/skills/service-itsm-teams-employee-agent-configure/references/teams-embedded-employee-agent.md +480 -0
  135. package/skills/service-itsm-teams-itdesk-configure/SKILL.md +232 -0
  136. package/skills/service-itsm-teams-itservice-configure/SKILL.md +391 -0
@@ -0,0 +1,148 @@
1
+ # Specialized Employee agent template catalog (ITSM)
2
+
3
+ The Employee side of `GET /connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent`
4
+ returns the **broad** IT Service Employee template plus specialized templates
5
+ as siblings in `data[]`. This catalog lists only entries under the
6
+ `svc_emp_intelligence__` namespace — the namespace this skill instantiates.
7
+ Every entry ships the same shape — `id`, `masterLabel`, `description`,
8
+ `topicsCount`, `actionsCount`, and a full `agentScript` YAML — and every one
9
+ of them carries the same `config.developer_name`/`config.agent_label`
10
+ substitution points the NGA bundle flow rewrites. That means **the same
11
+ create/publish/activate sequence used for the broad template works for any
12
+ specialized template** — the only difference is the `masterLabel` (and thus
13
+ the `id`) that Phases 1 and 4 pin against.
14
+
15
+ This reference is the picker menu for the specialization branch. The SKILL
16
+ body stays under budget by delegating the catalog here.
17
+
18
+ ## Selection rules
19
+
20
+ 1. **Key on `id`.** Present via `AskUserQuestion` keyed on `id` when a
21
+ keyword match returns multiple `svc_emp_intelligence__` templates — labels
22
+ like `Application Password Reset Assistance` vs `System Password Reset
23
+ Assistance` are close enough that a label-only picker can misread a
24
+ partial user phrase.
25
+ 2. **Ignore everything outside `svc_emp_intelligence__`.** The
26
+ `agent-templates` endpoint's `data[]` includes entries from other
27
+ namespaces (e.g. `svc_itsm_intelligence__`, `EmpSvcAgent__`,
28
+ `svc_itom_intelligence__`, `EmployeeCopilot__`, `agentforce_runtime_insights__`,
29
+ `approval_intelligence__`, `revcloud_insight_agent__`, `Slack__`,
30
+ `svc_coex_intel__`, `EmpSvcMcpAgent__`). These are NOT specialized
31
+ Employee templates instantiable by this skill and MUST NOT appear in
32
+ the picker — filter `data[]` to `id`s starting with `svc_emp_intelligence__`.
33
+ If the user asks for one of the `svc_itsm_intelligence__*` entries,
34
+ redirect to `service-itsm-agentic-setup-fulfiller-agent-configure`; the
35
+ rest are outside this skill's scope entirely.
36
+ 3. **Default developerName / label.** When the user picks a specialized
37
+ template by `id`, derive:
38
+ - `developerName` = the substring after `__` in `id`, snake-cased and
39
+ truncated ≤ 40 chars (e.g. `PasswordManagerAssistance` →
40
+ `Password_Manager_Assistance`). A user override still wins.
41
+ - `label` = the template's `masterLabel` verbatim (e.g.
42
+ `Password Manager Assistance`). A user override still wins.
43
+ 4. **Everything else is unchanged.** Phase 2's idempotency SOQL still keys
44
+ on the collected `<developerName>`; Phase 4 still passes the collected
45
+ `<masterLabel>` to `scripts/build-create-body.mjs`; Phases 5–7 are
46
+ byte-identical.
47
+
48
+ ## Category — Access & Identity
49
+
50
+ | Template `id` | Label | What it does |
51
+ |---|---|---|
52
+ | `svc_emp_intelligence__APIKeyAssistance` | API Key Assistance | Provision and manage API keys / auth tokens for internal + external services. |
53
+ | `svc_emp_intelligence__ApplicationPasswordResetAssistance` | Application Password Reset Assistance | Reset passwords for software applications specifically (app-level, not network). |
54
+ | `svc_emp_intelligence__CertificateManagementAssistance` | Certificate Management Assistance | Manage the lifecycle of digital certificates and SSL credentials. |
55
+ | `svc_emp_intelligence__OktaUserManagementAssistance` | Okta User Management Assistance | Manage Okta user accounts, groups, and account statuses. |
56
+ | `svc_emp_intelligence__PasswordManagerAssistance` | Password Manager Assistance | Manage credentials in corporate password managers (update, delete, sync). |
57
+ | `svc_emp_intelligence__PrivilegeAccessAssistance` | Privilege Access Assistance | Elevated privileges + hardware access rights lifecycle. |
58
+ | `svc_emp_intelligence__SSOAssistance` | SSO Assistance | Report login failures and troubleshoot identity-protected service access. |
59
+ | `svc_emp_intelligence__SystemAndFileAccessAssistance` | System and File Access Assistance | File shares, DB privileges, AD group management, revocation. |
60
+ | `svc_emp_intelligence__SystemPasswordResetAssistance` | System Password Reset Assistance | Reset network / system passwords + MFA settings. |
61
+
62
+ ## Category — Devices & Endpoints
63
+
64
+ | Template `id` | Label | What it does |
65
+ |---|---|---|
66
+ | `svc_emp_intelligence__DeviceReturnAssistance` | Device Return Assistance | Return corporate hardware (upgrades, repairs, offboarding). |
67
+ | `svc_emp_intelligence__DeviceSecurityAssistance` | Device Security Assistance | MDM enrollment + rapid threat response. |
68
+ | `svc_emp_intelligence__DeviceTroubleshootingAssistance` | Device Troubleshooting Assistance | Troubleshoot HW issues, install monitoring agents. |
69
+ | `svc_emp_intelligence__EndpointAssistance` | Endpoint Assistance | Workstation health monitoring + inventory. |
70
+ | `svc_emp_intelligence__HardwareRequestAssistance` | Hardware Request Assistance | Request new/loaner hardware (laptops, peripherals, docks). |
71
+ | `svc_emp_intelligence__LaptopRefreshAssistance` | Laptop Refresh Assistance | Scheduled laptop / monitor replacements. |
72
+ | `svc_emp_intelligence__LostDeviceAssistance` | Lost Device Assistance | Report lost/stolen devices, execute remote sanitization. |
73
+
74
+ ## Category — Software & Applications
75
+
76
+ | Template `id` | Label | What it does |
77
+ |---|---|---|
78
+ | `svc_emp_intelligence__ApplicationSupportAssistance` | Application Support Assistance | KB troubleshooting for third-party platforms; escalate to incident. |
79
+ | `svc_emp_intelligence__GoogleWorkspaceAssistance` | Google Workspace Assistance | Provision Workspace resources, manage groups, data transfer. |
80
+ | `svc_emp_intelligence__InternalApplicationsAssistance` | Internal Applications Assistance | Support proprietary / in-house apps. |
81
+ | `svc_emp_intelligence__JiraAssistance` | Jira Assistance | Provision access, automate issue creation with custom fields. |
82
+ | `svc_emp_intelligence__LicenseAuditAssistance` | License Audit Assistance | Track user entitlements, reclaim unused licenses. |
83
+ | `svc_emp_intelligence__Office365SupportAssistance` | Office 365 Support Assistance | Diagnose Outlook/Teams/OneDrive/Office issues. |
84
+ | `svc_emp_intelligence__ProjectManagementToolAssistance` | Project Management Tool Assistance | Provision Asana/Trello/Miro boards. |
85
+ | `svc_emp_intelligence__SalesforceHelpAssistance` | Salesforce Help Assistance | Salesforce user lifecycle + platform troubleshooting. |
86
+ | `svc_emp_intelligence__SharepointAssistance` | Sharepoint Assistance | SharePoint site lifecycle + permissions. |
87
+ | `svc_emp_intelligence__SoftwareAssistance` | Software Assistance | Software installations, updates, license renewals, evaluations. |
88
+
89
+ ## Category — Infrastructure & Networking
90
+
91
+ | Template `id` | Label | What it does |
92
+ |---|---|---|
93
+ | `svc_emp_intelligence__CloudResourcesAssistance` | Cloud Resources Assistance | Provision VMs / storage, dev stacks, infra ops. |
94
+ | `svc_emp_intelligence__DataBackupAssistance` | Data Backup Assistance | Ad-hoc backups + VM backup schedules. |
95
+ | `svc_emp_intelligence__InfrastructureProvisioningAssistance` | Infrastructure Provisioning Assistance | Provisioning-focused: VMs, test envs. |
96
+ | `svc_emp_intelligence__LogAccessAssistance` | Log Access Assistance | Secure retrieval of system/app/infra logs. |
97
+ | `svc_emp_intelligence__NetworkingAssistance` | Networking Assistance | Network connectivity, VPN, network resource permissions. |
98
+ | `svc_emp_intelligence__ServerStatusAssistance` | Server Status Assistance | Monitor CI health via CMDB. |
99
+
100
+ ## Category — Workplace & Facilities
101
+
102
+ | Template `id` | Label | What it does |
103
+ |---|---|---|
104
+ | `svc_emp_intelligence__AudiovisualSupportAssistance` | Audiovisual Support Assistance | AV support — meeting-room HW, connectivity, calibration. |
105
+ | `svc_emp_intelligence__BadgeAccessAssistance` | Badge Access Assistance | Physical badge issuance / replacement / troubleshooting. |
106
+ | `svc_emp_intelligence__FacilitiesAssistance` | Facilities Assistance | Non-IT: climate, cleaning, physical maintenance. |
107
+ | `svc_emp_intelligence__GuestCheckinAssistance` | Guest Check-in Assistance | Guest registration + visitor Wi-Fi. |
108
+ | `svc_emp_intelligence__OfficeRelocationAssistance` | Office Relocation Assistance | IT infra moves + HW logistics for relocations. |
109
+ | `svc_emp_intelligence__PhoneAssistance` | Phone Assistance | Corporate telephony + desk-phone HW. |
110
+ | `svc_emp_intelligence__PrinterAssistance` | Printer Assistance | Printing issues + printer installs + supplies. |
111
+
112
+ ## Category — Communications & Collaboration
113
+
114
+ | Template `id` | Label | What it does |
115
+ |---|---|---|
116
+ | `svc_emp_intelligence__DistributionListAssistance` | Distribution List Assistance | Slack/Teams workspaces, email lists, shared mailboxes. |
117
+ | `svc_emp_intelligence__MobilePlanAssistance` | Mobile Plan Assistance | Cellular plans, roaming, data add-ons. |
118
+
119
+ ## Category — Employee Lifecycle & HR
120
+
121
+ | Template `id` | Label | What it does |
122
+ |---|---|---|
123
+ | `svc_emp_intelligence__OffboardingAssistance` | Offboarding Assistance | Offboarding intake. |
124
+ | `svc_emp_intelligence__OnboardingAssistance` | Onboarding Assistance | New-hire onboarding intake. |
125
+ | `svc_emp_intelligence__VendorEmployeeAssistance` | Vendor Employee Assistance | External partner / contractor access lifecycle. |
126
+
127
+ ## Category — Analytics, Approvals, Knowledge
128
+
129
+ | Template `id` | Label | What it does |
130
+ |---|---|---|
131
+ | `svc_emp_intelligence__AnalyticsWorkspaceAssistance` | Analytics Workspace Assistance | Tableau site provisioning + workspace access. |
132
+ | `svc_emp_intelligence__ITApprovalAssistance` | IT Approval Assistance | Approve/reject pending IT requests in-chat. |
133
+ | `svc_emp_intelligence__ITPolicyAssistance` | IT Policy Assistance | Company policy Q&A + exception requests. |
134
+ | `svc_emp_intelligence__KnowledgeAssistance` | Knowledge Assistance | KB search + summarization. |
135
+ | `svc_emp_intelligence__CorporateCardManagementAssistance` | Corporate Card Management Assistance | Corporate credit card requests / admin. |
136
+
137
+ ## Category — Security & Compliance
138
+
139
+ | Template `id` | Label | What it does |
140
+ |---|---|---|
141
+ | `svc_emp_intelligence__SecurityAssistance` | Security Assistance | Report incidents (phishing/breach), security training + exceptions. |
142
+
143
+ ## Category — Ticketing (broad self-service)
144
+
145
+ | Template `id` | Label | What it does |
146
+ |---|---|---|
147
+ | `svc_emp_intelligence__TicketManagementAssistance` | Ticket Management Assistance | Broad ticket lifecycle: status, reopens, comments, intake. |
148
+ | `svc_emp_intelligence__ItEmployeeAssistance` | IT Service Employee | **Default / broad** — the umbrella IT-Service Employee assistant. This is the SKILL's default when no specialization is requested. |
@@ -0,0 +1,169 @@
1
+ # Employee Agent — Workflow Detail
2
+
3
+ Detailed per-phase command shapes + verdict narrative for `service-itsm-agentic-setup-employee-agent-configure`. Read this alongside the phase headers in `SKILL.md` — the SKILL body holds the load-bearing rules, this file holds the exact commands and branch-by-branch verdict handling.
4
+
5
+ All calls go through `sf`; substitute `<alias>` with the collected target org and `<developerName>` / `<label>` with the collected values.
6
+
7
+ ## Phase 0 — Establish the per-run scratch directory
8
+
9
+ Before any phase writes a transient JSON file, invoke `scripts/create-scratch-dir.mjs` — path selection (`${TMPDIR}` → `/tmp` → `${outputDir}` last-resort, keeping transient captures out of the scored `${outputDir}` tree) and the `mkdtemp` call live in the helper so the deterministic logic never sits in prose (A9). Every subsequent phase writes its scratch JSON under `${SCRATCH_DIR}`, so runs never collide and the transient state stays scoped to the run:
10
+
11
+ ```bash
12
+ SCRATCH_DIR="$(node "<skill_dir>/scripts/create-scratch-dir.mjs" "${outputDir:-}")"
13
+ ```
14
+
15
+ The remaining phases reference `${SCRATCH_DIR}` for every transient path (studio-access, agent-templates, bot-existing, create-bundle-body, publish/activate response captures, report-state, verify). The **durable** run artifact — `${outputDir}/report.md` — is still written to the harness-provided directory.
16
+
17
+ ## Phase 1 — Preflight: confirm Studio access + template provisioning
18
+
19
+ Capture the Studio-access read and the `agent-templates` read, then let `scripts/classify-preflight.mjs` make the deterministic decisions (never parse `hasAccess` or search `data[]` in prose — A9). The `agent-templates` `agentType` query param is **required** with value `AgentforceEmployeeAgent` (a call without it returns `400 MISSING_ARGUMENT: agentType`):
20
+
21
+ ```bash
22
+ sf api request rest "/services/data/v67.0/agentforce-studio/access/Agents" \
23
+ --method GET --target-org <alias> > ${SCRATCH_DIR}/studio-access.json 2>${SCRATCH_DIR}/studio-access.err || true
24
+ sf api request rest "/services/data/v67.0/connect/service-itsm/agent-templates?agentType=AgentforceEmployeeAgent" \
25
+ --method GET --target-org <alias> > ${SCRATCH_DIR}/agent-templates.json 2>${SCRATCH_DIR}/agent-templates.err || true
26
+ node "<skill_dir>/scripts/classify-preflight.mjs" ${SCRATCH_DIR}/studio-access.json ${SCRATCH_DIR}/agent-templates.json "<masterLabel>"
27
+ ```
28
+
29
+ Pass the resolved `<masterLabel>` — `"IT Service Employee"` for the default broad path, or the picked specialized template's `masterLabel` (e.g. `"Password Manager Assistance"`) for a specialized path. The classifier matches `data[]` case-insensitively on `masterLabel` and confirms the matched row has a non-empty `agentScript`.
30
+
31
+ The classifier prints `{ studio:{hasAccess,signal}, template:{present,id,hasAgentScript,botDefinitionId,signal}, verdict, reasons }`:
32
+
33
+ - `template.hasAgentScript:true` confirms the template carries the Agent Script content Phase 4 needs; capture the raw `agent-templates.json` file path — Phase 4 re-reads it directly (via `scripts/build-create-body.mjs`) rather than the classifier re-emitting the full script content.
34
+ - **`template.botDefinitionId` is the PRIMARY Phase-2 idempotency key.** A populated value means this template has already been instantiated into a live `BotDefinition` (the broad Employee agent ships pre-provisioned this way); a `null` value means it has not been created yet OR it was created by this skill (self-created agents never back-fill the template row). Capture `botDefinitionId` for Phase 2, and carry the collected `<developerName>` as the fallback key.
35
+ - `verdict:"READY"` ⇒ continue to Phase 2.
36
+ - `verdict:"ERROR"` because `studio.signal="ERROR"` (the Studio-access read returned a parseable but non-404 error body — e.g. `401`/`403`) ⇒ do NOT proceed — surface the raw error and stop. This is a failed prerequisite read, not an unwired gate; do not let a present template push the verdict to READY.
37
+ - `verdict:"NOT-READY"` because `studio.signal="FAIL"` (`hasAccess=false`) ⇒ do NOT proceed — **offer the prerequisite hand-off**:
38
+ - Present a single `AskUserQuestion`: _"Agentforce for IT Service prerequisites don't look satisfied on this org. Run `service-itsm-agentic-setup-agentforce-studio-validate` (employee path) to check readiness first?"_ (options: **Yes, check readiness** / **No, stop here**).
39
+ - On **Yes**: delegate to `service-itsm-agentic-setup-agentforce-studio-validate` (read-only readiness check, `employee` agent path). If it reports NOT-READY, stop and report the missing prerequisite (enablement is a Setup-UI/admin action, outside both skills' write scope). If READY, resume from Phase 2.
40
+ - On **No**: stop and report the missing prerequisite verbatim — no writes.
41
+ - `verdict:"NOT-READY"` because `template.signal="FAIL"` (empty/no matching template) ⇒ the org is not ITSM-provisioned; hand off to the readiness check.
42
+ - `template.signal="CANNOT-CONFIRM"` because the matched template has no `agentScript` ⇒ the NGA create has nothing to build from; surface this and stop (do not fall back to the legacy `createAgent` route — it is out of scope for this skill).
43
+ - `studio.signal="CANNOT-CONFIRM"` (a **confirmed** `404` — the access-check gate isn't wired on the org, expected on scratch orgs) does **not** block: a successful create/publish/activate is authoritative. A later `403 FUNCTIONALITY_NOT_ENABLED` on the write is the same signal as `hasAccess=false` — trigger the same hand-off offer.
44
+
45
+ ## Phase 2 — Idempotency: does the target agent already exist, and is it active?
46
+
47
+ Idempotency is keyed **PRIMARILY** on the template's `botDefinitionId` (captured in Phase 1) and **FALLS BACK** to the collected `<developerName>`. The `botDefinitionId` is the platform's authoritative link from the `agent-templates` row to the `BotDefinition` it was instantiated into — it catches the pre-provisioned broad Employee agent (which ships active under DeveloperName `IT_Service_Employee`, never matching the default guess `IT_Service_Employee_Agent`, so a name-only read would false-negative and the create would fail with `DUPLICATE_VALUE`). But that link is back-filled **only** for pre-provisioned agents — an agent this skill creates never stamps `templateName`, so its template `botDefinitionId` stays `null`; for that self-created case the `DeveloperName`-keyed fallback is the guard, so never short-circuit to create when `botDefinitionId` is absent.
48
+
49
+ - **`template.botDefinitionId` is empty/null** ⇒ fall back to a DeveloperName-keyed read (do **not** short-circuit to create — a self-created agent from a prior run has a null template `botDefinitionId` but still exists). The `BotVersions` subquery is required — omitting it leaves `needsActivation` permanently false and hides the reactivation path:
50
+ ```bash
51
+ sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE DeveloperName='<developerName>'" \
52
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-existing.json 2>${SCRATCH_DIR}/bot-existing.err || true
53
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-existing.json "" "<developerName>"
54
+ ```
55
+ - **`template.botDefinitionId` is present** ⇒ read the `BotDefinition` by Id **`OR` by the collected `<developerName>`** in one query, INCLUDING its latest version's status, then classify. The `OR DeveloperName=` clause is what catches a **dangling** template→BotDefinition link — a `botDefinitionId` whose target row was since deleted: the by-Id half returns nothing, but the live same-name agent still surfaces, so the classifier falls back to it (`matchedBy:"developerName"`) instead of concluding `exists:false` and letting the create collide with `DUPLICATE_VALUE`:
56
+ ```bash
57
+ 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>'" \
58
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-existing.json 2>${SCRATCH_DIR}/bot-existing.err || true
59
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-existing.json "<botDefinitionId>" "<developerName>"
60
+ ```
61
+
62
+ The classifier prints `{ exists, count, matchedBy, agentId, botDefinitionId, developerName, latestVersionId, latestVersionStatus, needsActivation }` — `matchedBy` is `"botDefinitionId"` | `"developerName"` | `null`, and `developerName` is the ACTUAL live agent's DeveloperName read from the record (e.g. `IT_Service_Employee`), surface it in the report rather than the collected guess:
63
+
64
+ - `exists:false` ⇒ proceed to Phase 3 (create path).
65
+ - `exists:true` and `needsActivation:false` (latest version `Active`) ⇒ **ALREADY-CREATED** — skip the write, fall through to Phase 7 verification.
66
+ - `exists:true` and `needsActivation:true` (latest version `Inactive`) ⇒ do **not** create a duplicate agent — go to Phase 2b to offer activating the existing version instead.
67
+ - A non-zero exit (exit 3) means the query itself failed — surface the raw CLI error, do not assume the agent is absent.
68
+
69
+ ## Phase 2b — Reactivation offer (existing agent found inactive)
70
+
71
+ Present the discovery to the user via `AskUserQuestion`: _"An Employee agent named `<developerName>` already exists but its latest version is Inactive. Activate the existing version instead of creating a new agent?"_ (options: **Yes, activate the existing version** / **No, stop here**).
72
+
73
+ - On **Yes**: activate the captured `latestVersionId` directly — no create/publish needed since the `BotDefinition`/`BotVersion` already exist:
74
+ ```bash
75
+ sf api request rest "/services/data/v67.0/connect/bot-versions/<latestVersionId>/activation" \
76
+ --method POST --body '{"status":"Active"}' \
77
+ --target-org <alias> > ${SCRATCH_DIR}/activate-existing.json 2>${SCRATCH_DIR}/activate-existing.err || true
78
+ ```
79
+ On success, skip Phases 3–6 entirely (no create/publish/confirm-to-write for a fresh agent) and go straight to Phase 7 to verify. Report the aggregate verdict as **ACTIVATED** in Phase 8, not CREATED.
80
+ - On **No**: stop and report the current state (agent exists, latest version Inactive) without any writes.
81
+
82
+ ## Phase 3 — Confirm-to-Write Checkpoint (REQUIRED, create path only)
83
+
84
+ **Before raising the confirmation gate**, if `${outputDir}` was provided (via the harness's generated-file location directive), render the report file via `scripts/render-report.mjs` with `verdict:"PENDING CONFIRMATION"` so it exists even if the harness parks at the question. Skip this write for interactive runs where no `${outputDir}` was passed. Report-state JSON shape lives in `references/report-format.md`.
85
+
86
+ ```bash
87
+ node "<skill_dir>/scripts/render-report.mjs" ${SCRATCH_DIR}/report-state.json "${outputDir}/report.md"
88
+ ```
89
+
90
+ Report-state JSON shape:
91
+
92
+ ```json
93
+ {
94
+ "org": "<alias>",
95
+ "template": {"masterLabel": "...", "id": "...", "kind": "broad umbrella"|"specialized"},
96
+ "developerName": "...",
97
+ "label": "...",
98
+ "preflight": {"studioHasAccess": true|false, "templateAgentScriptPresent": true|false},
99
+ "enumerate": {"existsBeforeWrite": true|false, "latestVersionStatus": "Active"|"Inactive"|"n/a"},
100
+ "confirmToWrite": "pending",
101
+ "verdict": "PENDING CONFIRMATION",
102
+ "reason": "Run is paused at the confirm-to-write gate awaiting the user's explicit \"yes\"."
103
+ }
104
+ ```
105
+
106
+ THEN **present the exact create request** (developerName + label, that this creates an NGA-native agent from the Employee template's Agent Script) and require an explicit "yes" via `AskUserQuestion`. **Proceed to Phase 4 ONLY on an explicit "yes".** On "no" (including "hold off on activation" / "not yet" / any decline of the atomic chain), stop and — if `${outputDir}` was provided — re-render with `verdict:"DECLINED"` and a one-line `reason` naming the user's decline. Never fabricate a partial "create-only" outcome.
107
+
108
+ ## Phase 4 — Create the NGA bundle
109
+
110
+ Build the `createBundleWithVersion` request body with the helper — it re-reads the Phase-1 `agent-templates.json`, extracts the matched template's `agentScript`, fully HTML-decodes it, and substitutes its internal `config.developer_name` / `config.agent_label` with the **collected** `<developerName>` / `<label>` (so the bundle's outer `apiName` and the script's internal identity match). This also keeps the large script content and any free-text quotes/apostrophes out of an inline shell string:
111
+
112
+ ```bash
113
+ node "<skill_dir>/scripts/build-create-body.mjs" ${SCRATCH_DIR}/agent-templates.json "<masterLabel>" "<developerName>" "<label>" ${SCRATCH_DIR}/create-bundle-body.json
114
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundles" \
115
+ --method POST \
116
+ --body @${SCRATCH_DIR}/create-bundle-body.json \
117
+ --target-org <alias> > ${SCRATCH_DIR}/create-bundle.json 2>${SCRATCH_DIR}/create-bundle.err || true
118
+ ```
119
+
120
+ Pass the same resolved `<masterLabel>` used in Phase 1 — the builder re-reads `${SCRATCH_DIR}/agent-templates.json`, re-locates the row by `masterLabel`, decodes its `agentScript`, and substitutes the collected `<developerName>`/`<label>` into the script's internal `config.developer_name`/`config.agent_label` before writing the bundle body.
121
+
122
+ On success, the `POST /nextgen-authoring/bundles` response is a bundle-version detail: `{ apiName, label, bundleId, id, versionStatus:"DRAFT", assets:[...], ... }`. **Capture `id` — that is the `bundleVersionId` used in Phases 5 and 6, not `bundleId`.**
123
+
124
+ - `403 FUNCTIONALITY_NOT_ENABLED` / `404` → trigger the Phase-1 prerequisite hand-off offer (the NGA authoring namespace isn't provisioned on the org).
125
+ - A build-script exit 3 (template or `agentScript` not found in `${SCRATCH_DIR}/agent-templates.json`) → surface the script's stderr verbatim and stop; do not retry with a hand-typed template id.
126
+
127
+ ## Phase 5 — Publish the bundle version
128
+
129
+ Publish the captured `bundleVersionId` — empty `--body '{}'` required (the CLI rejects a POST with no `--body`):
130
+
131
+ ```bash
132
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/publish" \
133
+ --method POST --body '{}' \
134
+ --target-org <alias> > ${SCRATCH_DIR}/publish-bundle.json 2>${SCRATCH_DIR}/publish-bundle.err || true
135
+ ```
136
+
137
+ On success: `{ lastPublishedOn, publishedBotId, publishedBotVersionId }`. This is the call that creates the underlying `BotDefinition`/`BotVersion`. An error here means the DRAFT version failed platform-side validation — surface it verbatim; do not attempt to activate an unpublished version.
138
+
139
+ ## Phase 6 — Activate the bundle version
140
+
141
+ Activate the same `bundleVersionId`:
142
+
143
+ ```bash
144
+ sf api request rest "/services/data/v67.0/nextgen-authoring/bundle-versions/<bundleVersionId>/activate" \
145
+ --method POST --body '{}' \
146
+ --target-org <alias> > ${SCRATCH_DIR}/activate-bundle.json 2>${SCRATCH_DIR}/activate-bundle.err || true
147
+ ```
148
+
149
+ Success returns an **empty body** — do not treat empty stdout as a failure; check the CLI exit code and fall through to Phase 7 to confirm via `BotDefinition`/`BotVersion` state instead of parsing a response payload.
150
+
151
+ ## Phase 7 — Verify the agent is live
152
+
153
+ Read `BotDefinition` by Id (with `BotVersions` subquery, same shape as Phase 2) and classify. The verify `<verifyId>` is the create path's **`publishedBotId`** (captured from the Phase-5 publish response) 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 `null` on a `matchedBy:"developerName"` fallback hit — using it would run the verify as `WHERE Id=''` and falsely report failure after a successful skip/activation). Never the collected `<developerName>`:
154
+
155
+ ```bash
156
+ sf data query -q "SELECT Id,DeveloperName,MasterLabel,(SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1) FROM BotDefinition WHERE Id='<verifyId>'" \
157
+ --target-org <alias> --json > ${SCRATCH_DIR}/bot-verify.json 2>${SCRATCH_DIR}/bot-verify.err || true
158
+ node "<skill_dir>/scripts/classify-agent-existence.mjs" ${SCRATCH_DIR}/bot-verify.json "<verifyId>"
159
+ ```
160
+
161
+ Confirm `exists:true` with `count:1`, and — on the create or reactivation path — `latestVersionStatus:"Active"`. `exists:false` after a successful activate ⇒ report the discrepancy verbatim, do not fabricate success. Optionally cross-check `GET /nextgen-authoring/bundles` for an entry with the collected `apiName` and `isLegacy:false` to confirm the agent is NGA-native (no external-link icon in Agentforce Studio).
162
+
163
+ ## Phase 8 — Aggregate verdict
164
+
165
+ Report the verdict (CREATED / ALREADY-CREATED / ACTIVATED / FAILED) and the resulting `BotDefinition` Id / bundle `id`. Use **ACTIVATED** when Phase 2b's reactivation path was taken (existing agent found inactive, activated instead of creating new). Emit the final report by re-invoking `scripts/render-report.mjs` with the fully populated phase-state JSON. If `${outputDir}` was provided, overwrite `${outputDir}/report.md`; otherwise emit the helper's stdout as the turn-side report.
166
+
167
+ ```bash
168
+ node "<skill_dir>/scripts/render-report.mjs" ${SCRATCH_DIR}/report-state.json "${outputDir}/report.md"
169
+ ```
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ // Build the NGA createBundleWithVersion request body from the shipped
3
+ // Employee template's agentScript.
4
+ //
5
+ // The legacy `agent-templates` read already returns the template's full Agent
6
+ // Script (AFScript) content in its `agentScript` field, HTML-entity-encoded
7
+ // (sometimes double-encoded). This script:
8
+ // 1. Locates the matching template item by masterLabel in the
9
+ // agent-templates response.
10
+ // 2. Fully HTML-decodes `agentScript` (named + numeric entities, multi-pass
11
+ // to unwind double-encoding).
12
+ // 3. Substitutes the script's internal `config.developer_name` /
13
+ // `config.agent_label` with the collected <developerName> / <label> —
14
+ // the bundle's outer apiName must match the script's internal
15
+ // developer_name or the two diverge (the platform will otherwise
16
+ // auto-suffix the apiName).
17
+ // 4. Writes the createBundleWithVersion body
18
+ // { apiName, label, assets: [{ resourceName: "agentDefinition",
19
+ // resourceType: "agentDefinition", sections: [], resourceContent }] }
20
+ // to <outPath>.
21
+ //
22
+ // Usage:
23
+ // node build-create-body.mjs <agent-templates.json> <masterLabel> <developerName> <label> <outPath>
24
+ //
25
+ // Exits 2 on missing/bad args, 3 if the template or its agentScript can't be found.
26
+
27
+ import { readFileSync, writeFileSync } from 'node:fs';
28
+
29
+ const [templatesPath, masterLabel, developerName, label, outPath] = process.argv.slice(2);
30
+ if (!templatesPath || !masterLabel || !developerName || !label || !outPath) {
31
+ process.stderr.write('usage: node build-create-body.mjs <agent-templates.json> <masterLabel> <developerName> <label> <outPath>\n');
32
+ process.exit(2);
33
+ }
34
+
35
+ function decodeHtmlEntities(text) {
36
+ let prev = text;
37
+ for (let pass = 0; pass < 4; pass += 1) {
38
+ const next = prev
39
+ .replace(/&amp;/g, '&')
40
+ .replace(/&quot;/g, '"')
41
+ .replace(/&#39;/g, "'")
42
+ .replace(/&lt;/g, '<')
43
+ .replace(/&gt;/g, '>')
44
+ .replace(/&#(\d+);/g, (_, code) => String.fromCharCode(parseInt(code, 10)));
45
+ if (next === prev) break;
46
+ prev = next;
47
+ }
48
+ return prev;
49
+ }
50
+
51
+ let templatesData;
52
+ try {
53
+ templatesData = JSON.parse(readFileSync(templatesPath, 'utf8'));
54
+ } catch {
55
+ process.stderr.write(`error: could not read/parse ${templatesPath}\n`);
56
+ process.exit(3);
57
+ }
58
+
59
+ const items = Array.isArray(templatesData?.data) ? templatesData.data : [];
60
+ // Filter to `svc_emp_intelligence__` first — matches the preflight classifier.
61
+ // The agent-templates response also carries other-namespace entries; some
62
+ // share a masterLabel with an in-namespace entry (e.g. `System Password Reset
63
+ // Assistance`) so a `masterLabel`-only match would silently pick whichever
64
+ // appeared first in `data[]`.
65
+ const inNamespace = items.filter((it) => typeof it?.id === 'string' && it.id.startsWith('svc_emp_intelligence__'));
66
+ const wanted = String(masterLabel).trim().toLowerCase();
67
+ const match = inNamespace.find((it) => String(it?.masterLabel ?? '').trim().toLowerCase() === wanted);
68
+ if (!match) {
69
+ process.stderr.write(`error: no svc_emp_intelligence__ template with masterLabel "${masterLabel}" found in ${templatesPath}\n`);
70
+ process.exit(3);
71
+ }
72
+ if (!match.agentScript || typeof match.agentScript !== 'string' || !match.agentScript.trim()) {
73
+ process.stderr.write(`error: template "${masterLabel}" (id=${match.id}) has no agentScript content\n`);
74
+ process.exit(3);
75
+ }
76
+
77
+ // Escapes a value for use as a YAML double-quoted scalar — the agentScript's
78
+ // developer_name/agent_label fields are plain `"..."` strings, so a raw
79
+ // double-quote or backslash in a user-supplied label would otherwise break
80
+ // out of the scalar (e.g. label `Sam "Ops"` -> `agent_label: "Sam "Ops""`).
81
+ function yamlDoubleQuoteEscape(text) {
82
+ return String(text).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
83
+ }
84
+
85
+ const decoded = decodeHtmlEntities(match.agentScript);
86
+ const developerNameEscaped = yamlDoubleQuoteEscape(developerName);
87
+ const labelEscaped = yamlDoubleQuoteEscape(label);
88
+
89
+ const substituted = decoded
90
+ .replace(/developer_name:\s*"[^"]*"/, () => `developer_name: "${developerNameEscaped}"`)
91
+ .replace(/agent_label:\s*"[^"]*"/, () => `agent_label: "${labelEscaped}"`);
92
+
93
+ if (!substituted.includes(`developer_name: "${developerNameEscaped}"`)) {
94
+ process.stderr.write('error: failed to substitute config.developer_name in the decoded agentScript\n');
95
+ process.exit(3);
96
+ }
97
+ if (!substituted.includes(`agent_label: "${labelEscaped}"`)) {
98
+ process.stderr.write('error: failed to substitute config.agent_label in the decoded agentScript\n');
99
+ process.exit(3);
100
+ }
101
+
102
+ const body = {
103
+ apiName: developerName,
104
+ label,
105
+ assets: [
106
+ {
107
+ resourceName: 'agentDefinition',
108
+ resourceType: 'agentDefinition',
109
+ sections: [],
110
+ resourceContent: substituted,
111
+ },
112
+ ],
113
+ };
114
+
115
+ writeFileSync(outPath, JSON.stringify(body), 'utf8');
116
+ process.stdout.write(outPath + '\n');
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ // Deterministic idempotency / verification classifier for the Employee-agent create flow.
3
+ //
4
+ // Idempotency for this flow is keyed PRIMARILY on the TEMPLATE's own
5
+ // `botDefinitionId` — the platform's authoritative link from an `agent-templates`
6
+ // row to the live `BotDefinition` it was instantiated into — and FALLS BACK to a
7
+ // `DeveloperName`-keyed read when that row carries no `botDefinitionId`.
8
+ // The broad "IT Service Employee" agent is pre-provisioned+active under
9
+ // DeveloperName `IT_Service_Employee`, which does NOT match this skill's default
10
+ // collected developerName `IT_Service_Employee_Agent`; a DeveloperName-only read
11
+ // false-negatives on THAT agent (exists:false) and the create then collides on
12
+ // `apiName` with `DUPLICATE_VALUE` — hence botDefinitionId is the primary key.
13
+ // But botDefinitionId is back-filled onto the template row ONLY for platform-
14
+ // pre-provisioned agents: the ITSM create path never stamps `templateName`, so
15
+ // agents THIS skill creates keep a null template botDefinitionId forever, and a
16
+ // DeveloperName-keyed read is the reliable guard for them — used as the FALLBACK.
17
+ // (Preflight emits `template.botDefinitionId`; the workflow passes it as the
18
+ // primary key and the collected developerName as the fallback key.)
19
+ //
20
+ // This classifier consumes the raw JSON of a `sf data query ... --json` read of
21
+ // BotDefinition (BY Id primarily, BY DeveloperName on the fallback) and decides
22
+ // whether the agent already exists — and if so, whether its latest BotVersion is
23
+ // Inactive (so the workflow can offer to activate it instead of creating a
24
+ // duplicate). This is the deterministic decision that gates whether the write is
25
+ // skipped — it MUST NOT be interpreted by the model in prose (authoring standard A9).
26
+ //
27
+ // Usage:
28
+ // node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName]
29
+ //
30
+ // When <botDefinitionId> is empty, `-`, or the literal `null`/`undefined` (the
31
+ // matched template carries no botDefinitionId), the classifier FALLS BACK to
32
+ // keying on <developerName>, and <bot-query.json> must be a DeveloperName-keyed
33
+ // BotDefinition read: self-created agents are never back-filled with a
34
+ // botDefinitionId (the ITSM create path doesn't stamp `templateName`, so the
35
+ // platform never joins the agent-templates row to its BotDefinition), so
36
+ // DeveloperName is the only idempotency guard left for them. Only when BOTH
37
+ // <botDefinitionId> and <developerName> are absent is exists:false emitted
38
+ // without reading a query file. Otherwise <bot-query.json> is a FILE PATH to the
39
+ // stdout captured from:
40
+ // sf data query -q "SELECT Id,DeveloperName,MasterLabel,
41
+ // (SELECT Id,Status FROM BotVersions ORDER BY VersionNumber DESC LIMIT 1)
42
+ // FROM BotDefinition WHERE Id='<botDefinitionId>' OR DeveloperName='<developerName>'" \
43
+ // --target-org <org> --json > file.json
44
+ // (The present-id read ORs in DeveloperName so a DANGLING template→BotDefinition
45
+ // link — a botDefinitionId whose target BotDefinition was since deleted — still
46
+ // surfaces the live same-name agent: the classifier tries the Id first, then
47
+ // falls back to the name on the SAME records. The pure FALLBACK read, taken when
48
+ // the template row carries no botDefinitionId at all, keys on
49
+ // `DeveloperName='<developerName>'` only; everything else is identical.
50
+ // `sf data query --json` wraps results in a `.result.records[]` envelope. The
51
+ // BotVersions subquery is required so this classifier can see the latest
52
+ // version's Status — a query without it leaves latestVersionStatus null and
53
+ // needsActivation false, which silently disables the reactivation path.)
54
+ //
55
+ // Emits a single JSON object to stdout:
56
+ // { exists, count, matchedBy, agentId, botDefinitionId, developerName, latestVersionId, latestVersionStatus, needsActivation }
57
+ // where exists is true|false, developerName is the ACTUAL DeveloperName read
58
+ // from the matched record (e.g. `IT_Service_Employee`) — NOT the collected
59
+ // guess — so the report surfaces the live agent's real identity;
60
+ // latestVersionStatus is "Active"|"Inactive"|null (null means no BotVersion
61
+ // child row was returned), and needsActivation is true only when exists is true
62
+ // AND latestVersionStatus is "Inactive" — the signal to offer activating the
63
+ // existing version instead of creating a new agent. `matchedBy` is
64
+ // "botDefinitionId" | "developerName" | null, recording which key hit. Exit code
65
+ // is always 0 on a parseable body (or when neither key is supplied); the verdict
66
+ // is carried in the payload. On an unparseable/failed query it exits 3 so the
67
+ // workflow surfaces the raw error rather than assuming NOT-EXISTS.
68
+
69
+ import { readFileSync } from 'node:fs';
70
+
71
+ const [queryPath, rawBotDefinitionId, rawDeveloperName] = process.argv.slice(2);
72
+ if (!queryPath) {
73
+ process.stderr.write('usage: node classify-agent-existence.mjs <bot-query.json> <botDefinitionId> [developerName]\n');
74
+ process.exit(2);
75
+ }
76
+
77
+ // Salesforce Ids compare on their case-sensitive 15-char base (the trailing 3
78
+ // chars are a case-normalizing checksum), so a 15-char and an 18-char form of
79
+ // the same record compare equal on the first 15 chars.
80
+ function idKey(v) {
81
+ return String(v ?? '').trim().slice(0, 15);
82
+ }
83
+
84
+ function notSet(v) {
85
+ const s = String(v ?? '').trim().toLowerCase();
86
+ return s === '' || s === '-' || s === 'null' || s === 'undefined';
87
+ }
88
+
89
+ const botDefinitionId = String(rawBotDefinitionId ?? '').trim();
90
+ const developerName = String(rawDeveloperName ?? '').trim();
91
+ const noId = notSet(botDefinitionId);
92
+ const noName = notSet(developerName);
93
+
94
+ const NOT_EXISTS = {
95
+ exists: false,
96
+ count: 0,
97
+ matchedBy: null,
98
+ agentId: null,
99
+ botDefinitionId: null,
100
+ developerName: null,
101
+ latestVersionId: null,
102
+ latestVersionStatus: null,
103
+ needsActivation: false,
104
+ };
105
+
106
+ // Nothing to key on — no botDefinitionId AND no developerName fallback. There is
107
+ // no way to detect an existing agent, so this is the create path. (The workflow
108
+ // should always pass the collected developerName so the fallback below can run;
109
+ // this bare branch only fires when neither key is supplied.)
110
+ if (noId && noName) {
111
+ process.stdout.write(JSON.stringify(NOT_EXISTS, null, 2) + '\n');
112
+ process.exit(0);
113
+ }
114
+
115
+ let data;
116
+ try {
117
+ const text = readFileSync(queryPath, 'utf8').trim();
118
+ data = text ? JSON.parse(text) : null;
119
+ } catch {
120
+ process.stderr.write(`error: could not read/parse ${queryPath}\n`);
121
+ process.exit(3);
122
+ }
123
+
124
+ // A failed `sf data query --json` has status !== 0 (e.g. malformed SOQL, auth error).
125
+ // Do NOT treat that as "agent does not exist" — surface it.
126
+ if (!data || (typeof data.status === 'number' && data.status !== 0) || data.result === undefined) {
127
+ process.stderr.write('error: query did not return a results envelope; surface the raw CLI error and stop\n');
128
+ process.exit(3);
129
+ }
130
+
131
+ const records = Array.isArray(data.result?.records) ? data.result.records : [];
132
+
133
+ // PRIMARY key: the template's `botDefinitionId` (the platform's authoritative
134
+ // template→BotDefinition link) — catches the pre-provisioned broad agent whose
135
+ // live DeveloperName differs from this skill's collected guess.
136
+ // FALLBACK: the collected DeveloperName. Self-created agents are NOT
137
+ // back-filled — the ITSM create path never stamps `templateName`, so the
138
+ // platform never joins the agent-templates row to its BotDefinition and
139
+ // `botDefinitionId` stays null on every later read — so DeveloperName is their
140
+ // only guard. We ALSO fall back to DeveloperName when a PRESENT botDefinitionId
141
+ // matches nothing (a dangling link whose target BotDefinition was deleted): the
142
+ // present-id Phase-2 SOQL reads `WHERE Id=... OR DeveloperName=...`, so a stale
143
+ // link still surfaces the live same-name agent instead of slipping through to the
144
+ // create path and colliding with DUPLICATE_VALUE. Try the Id first, then the
145
+ // name; each filter is self-checking on top of the SOQL WHERE so a wrong-keyed
146
+ // read can't false-positive.
147
+ let matches = [];
148
+ let matchedBy = null;
149
+ if (!noId) {
150
+ const wantedIdKey = idKey(botDefinitionId);
151
+ matches = records.filter((r) => idKey(r?.Id) === wantedIdKey);
152
+ if (matches.length) matchedBy = 'botDefinitionId';
153
+ }
154
+ if (!matches.length && !noName) {
155
+ // DeveloperName uniqueness is case-insensitive; compare accordingly.
156
+ const wantedName = developerName.toLowerCase();
157
+ matches = records.filter((r) => String(r?.DeveloperName ?? '').trim().toLowerCase() === wantedName);
158
+ if (matches.length) matchedBy = 'developerName';
159
+ }
160
+ const exists = matches.length > 0;
161
+
162
+ // The BotVersions child subquery (if present in the SOQL) surfaces the latest
163
+ // version's Status so we can tell "already created and active" apart from
164
+ // "already created but inactive" — the latter should offer reactivation
165
+ // instead of a silent ALREADY-CREATED skip. The actual BotVersion status is
166
+ // authoritative over the template's `isActivated` flag.
167
+ const latestVersion = exists ? matches[0]?.BotVersions?.records?.[0] ?? null : null;
168
+ const latestVersionStatus = latestVersion?.Status ?? null;
169
+ const needsActivation = exists && latestVersionStatus === 'Inactive';
170
+
171
+ process.stdout.write(JSON.stringify({
172
+ exists,
173
+ count: matches.length,
174
+ // Which key matched — `botDefinitionId` (primary) or `developerName` (the
175
+ // fallback for self-created agents). null when nothing matched.
176
+ matchedBy: exists ? matchedBy : null,
177
+ agentId: exists ? (matches[0].Id ?? null) : null,
178
+ // On a DeveloperName-fallback hit this surfaces the live BotDefinition Id the
179
+ // template row was missing; on the Id path it echoes the queried id.
180
+ botDefinitionId: exists ? (matches[0].Id ?? null) : (noId ? null : botDefinitionId),
181
+ developerName: exists ? (matches[0].DeveloperName ?? null) : null,
182
+ latestVersionId: latestVersion?.Id ?? null,
183
+ latestVersionStatus,
184
+ needsActivation,
185
+ }, null, 2) + '\n');