@salesforce/afv-skills 1.57.0 → 1.59.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/agentforce-bot-upgrade/SKILL.md +3 -1
- package/skills/agentforce-generate/SKILL.md +21 -1
- package/skills/agentforce-generate/references/known-issues.md +51 -1
- package/skills/agentforce-generate/references/legacy-nga-regression-eval.md +547 -0
- package/skills/agentforce-generate/references/upgrade-legacy-agent-to-agentscript.md +577 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-analyze.py +404 -0
- package/skills/agentforce-generate/scripts/upgrade-legacy-nga-run-trials.sh +58 -0
- package/skills/agentforce-persona-generate/SKILL.md +505 -0
- package/skills/agentforce-persona-generate/assets/checklist-template.md +100 -0
- package/skills/agentforce-persona-generate/assets/persona-encoding-template.md +252 -0
- package/skills/agentforce-persona-generate/assets/persona-template.md +229 -0
- package/skills/agentforce-persona-generate/assets/sample-dialog-template.md +50 -0
- package/skills/agentforce-persona-generate/assets/workshop-outline-template.md +97 -0
- package/skills/agentforce-persona-generate/examples/concierge-persona.md +189 -0
- package/skills/agentforce-persona-generate/examples/concierge-sample-dialog.md +70 -0
- package/skills/agentforce-persona-generate/examples/drover-persona.md +194 -0
- package/skills/agentforce-persona-generate/examples/drover-sample-dialog.md +62 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-persona.md +188 -0
- package/skills/agentforce-persona-generate/examples/steady-hand-sample-dialog.md +68 -0
- package/skills/agentforce-persona-generate/examples/yt-persona.md +195 -0
- package/skills/agentforce-persona-generate/examples/yt-sample-dialog.md +66 -0
- package/skills/agentforce-persona-generate/references/attributions.md +36 -0
- package/skills/agentforce-persona-generate/references/interaction-design-notes.md +30 -0
- package/skills/agentforce-persona-generate/references/persona-encoding-guide.md +566 -0
- package/skills/agentforce-persona-generate/references/persona-framework.md +796 -0
- package/skills/agentforce-persona-generate/references/refinement-mappings.md +31 -0
- package/skills/agentforce-persona-generate/references/scoring-rubric.md +58 -0
- package/skills/agentforce-persona-generate/references/voice-catalog.json +2327 -0
- package/skills/agentforce-persona-generate/references/workshop-question-policy.md +90 -0
- package/skills/agentforce-persona-generate/references/workshop-scenario-seeds.md +119 -0
- package/skills/agentforce-persona-generate/scripts/parse_agent_yaml.py +223 -0
- package/skills/dx-app-analytics-query/SKILL.md +8 -8
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +12 -12
- package/skills/experience-ui-bundle-app-coordinate/references/phase-completion-validation.md +3 -3
- package/skills/experience-ui-bundle-app-coordinate/references/phase-execution-pattern.md +9 -7
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.mjs +132 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.mjs +62 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.mjs +71 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.mjs +95 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.mjs +78 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.mjs +21 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.mjs +28 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +3 -1
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.mjs +40 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +7 -5
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.mjs +70 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.mjs +76 -0
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.mjs +115 -0
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +7 -3
- package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.mjs +43 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.mjs +131 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.mjs +152 -0
- package/skills/experience-ui-bundle-mfa-configure/references/branding.md +10 -6
- package/skills/experience-ui-bundle-project-generate/SKILL.md +13 -39
- package/skills/experience-ui-bundle-project-generate/scripts/flatten-project.mjs +33 -11
- package/skills/experience-ui-bundle-project-generate/scripts/generate-project.mjs +77 -0
- package/skills/experience-ui-bundle-project-generate/scripts/install-deps.mjs +95 -0
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +1 -0
- package/skills/service-omni-command-center-analyze/SKILL.md +1 -0
- package/skills/service-omni-command-center-configure/SKILL.md +92 -0
- package/skills/service-omni-command-center-configure/references/api-notes.md +50 -0
- package/skills/service-omni-command-center-configure/scripts/configure-and-report.sh +257 -0
- package/skills/service-omni-command-center-configure/scripts/settings_document.py +97 -0
- package/skills/service-omni-command-center-configure/scripts/tests/test_command_center_configure_contracts.py +206 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-dangling-refs.sh +0 -42
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +0 -26
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-1-complete.sh +0 -35
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-4-complete.sh +0 -47
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-phase-6-ready.sh +0 -33
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-prerequisites.sh +0 -20
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +0 -15
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.sh +0 -30
- package/skills/experience-ui-bundle-frontend-generate/scripts/check-preconditions.sh +0 -37
- package/skills/experience-ui-bundle-frontend-generate/scripts/resolve-ui-bundle.sh +0 -66
- package/skills/experience-ui-bundle-frontend-generate/scripts/verify-rules.sh +0 -58
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +0 -30
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +0 -73
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +0 -118
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-project-generate
|
|
3
|
-
description: "Generates a minimal, ready-to-develop SFDX starter project from template instead of hand-scaffolding files. Use this skill when starting a brand-new Salesforce UI bundle app (React or Angular) and the initial project must be scaffolded — trigger phrases include create, start, or scaffold a new UI bundle app, generate a starter project, or use a prebuilt/starter template. DO NOT TRIGGER when: editing, styling, or adding pages or components to an EXISTING app (use experience-ui-bundle-frontend-generate); configuring ui-bundle.json or metadata files (use experience-ui-bundle-metadata-generate); deploying to an org (use experience-ui-bundle-deploy);
|
|
3
|
+
description: "Generates a minimal, ready-to-develop SFDX starter project from template instead of hand-scaffolding files. Use this skill when starting a brand-new Salesforce UI bundle app (React or Angular) and the initial project must be scaffolded — trigger phrases include create, start, or scaffold a new UI bundle app, generate a starter project, or use a prebuilt/starter template. DO NOT TRIGGER when: editing, styling, or adding pages or components to an EXISTING app (use experience-ui-bundle-frontend-generate); configuring ui-bundle.json or metadata files (use experience-ui-bundle-metadata-generate); deploying to an org (use experience-ui-bundle-deploy); when the user explicitly says they want to hand-scaffold from scratch; or when creating a brand-new standalone Salesforce project that also needs full setup — relocating the session, connecting an org, setting the default, and enabling source tracking (use dx-project-create in the salesforce-development plugin)."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.2"
|
|
6
6
|
domains: ["Experience"]
|
|
@@ -42,39 +42,22 @@ Once the user picks, carry the chosen `--template` flag into Step 2.
|
|
|
42
42
|
|
|
43
43
|
## Step 2: Generate the project into the target root
|
|
44
44
|
|
|
45
|
-
The project contents must land **directly at the target root `$DEST`** — so `sfdx-project.json` sits at `$DEST/sfdx-project.json`, with no extra wrapper subfolder. `sf template generate project` always nests its output under a `--name` subfolder, so generate into
|
|
45
|
+
The project contents must land **directly at the target root `$DEST`** — so `sfdx-project.json` sits at `$DEST/sfdx-project.json`, with no extra wrapper subfolder. `sf template generate project` always nests its output under a `--name` subfolder, so `<SKILL_DIR>/scripts/generate-project.mjs` generates into `$DEST`, flattens the subfolder's contents up into `$DEST` (overwriting anything already there on conflict), and removes the now-empty subfolder — all through Node's `fs`/`child_process` APIs, so it runs the same way on Windows cmd/PowerShell as it does on macOS/Linux/Git Bash.
|
|
46
46
|
|
|
47
47
|
- `<SKILL_DIR>` = the absolute path to **this skill's own directory** — the folder containing this `SKILL.md`; resolve it from the skill path in context
|
|
48
48
|
- **`$NAME`** — the project name (alphanumerical only — no spaces, hyphens, underscores, or special characters). Ask the user for it. It also names the UI bundle, so it shows up inside the project.
|
|
49
49
|
- **`$DEST`** — the target root directory the contents land in (use `.` for the current directory).
|
|
50
|
+
- **`$TEMPLATE`** — the `--template` flag value from the framework reference chosen in Step 1 (e.g. `reactinternalapp`).
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
NAME=MyApp # project name the user chose; also names the UI bundle
|
|
53
|
-
DEST=. # target root directory (the contents land directly here, no NAME/ wrapper)
|
|
54
|
-
|
|
55
|
-
# the --template flag from the framework reference chosen in Step 1
|
|
56
|
-
TEMPLATE=reactinternalapp # example placeholder — replace with the flag from your Step-1 reference
|
|
57
|
-
|
|
58
|
-
mkdir -p "$DEST"
|
|
59
|
-
sf template generate project --name "$NAME" --template "$TEMPLATE" --output-dir "$DEST"
|
|
60
|
-
|
|
61
|
-
# Flatten the generated $DEST/$NAME contents up into $DEST (see <SKILL_DIR>/scripts/flatten-project.mjs).
|
|
62
|
-
# Use the absolute skill-dir path — a relative ./scripts/ would resolve against $DEST, not the skill.
|
|
63
|
-
node "<SKILL_DIR>/scripts/flatten-project.mjs" "$DEST/$NAME" "$DEST"
|
|
64
|
-
rm -rf "$DEST/$NAME"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
> `<SKILL_DIR>/scripts/flatten-project.mjs` moves every generated entry (incl. dotfiles) into `$DEST`, overwriting any existing file/dir of any type on conflict while preserving unrelated files the user already had in `$DEST`. The per-entry `rmSync` + `renameSync` is what guarantees the template's files win on conflict (including a file-vs-directory type mismatch).
|
|
68
|
-
|
|
69
|
-
### Verify
|
|
70
|
-
|
|
71
|
-
After generation, confirm the contents landed at the root (not in a `$NAME/` subfolder):
|
|
52
|
+
Run the script with the actual, literal values substituted for `$NAME`, `$DEST`, and `$TEMPLATE` — do not use shell variable assignment/interpolation (`NAME=...` / `$NAME` / `%NAME%` / `$env:NAME`) since that syntax differs across bash, cmd, and PowerShell and this command must work in all three:
|
|
72
53
|
|
|
73
54
|
```sh
|
|
74
|
-
|
|
55
|
+
node "<SKILL_DIR>/scripts/generate-project.mjs" "<name>" "<dest>" "<template>"
|
|
75
56
|
```
|
|
76
57
|
|
|
77
|
-
`
|
|
58
|
+
The script prints `OK: project root landed at <dest> (...)` and exits 0 on success. It exits non-zero (with a clear stderr message) if `sf template generate project` fails, the generated project has no `sfdx-project.json`, or the flatten didn't leave a valid project root — stop and surface the failure rather than continuing.
|
|
59
|
+
|
|
60
|
+
`sfdx-project.json` must sit at `$DEST/sfdx-project.json`. The project also contains `package.json`, `force-app/main/default/uiBundles/$NAME/` (the UI bundle), `scripts/`, `config/`, and `README.md`. See the framework reference from Step 1 for the specific bundle contents.
|
|
78
61
|
|
|
79
62
|
## Step 3: Install dependencies (you do this — do NOT hand off uninstalled)
|
|
80
63
|
|
|
@@ -84,26 +67,17 @@ There are **multiple** `package.json` files, each needing its own install:
|
|
|
84
67
|
- the **project root** (`$DEST/package.json`), and
|
|
85
68
|
- the **UI bundle** dir under `$DEST/force-app/main/default/uiBundles/$NAME/` — this holds the toolchain the preview server loads, so it must have `node_modules` too.
|
|
86
69
|
|
|
87
|
-
|
|
88
|
-
# 1. project root ($DEST was set in Step 2)
|
|
89
|
-
( cd "$DEST" && npm install )
|
|
70
|
+
`<SKILL_DIR>/scripts/install-deps.mjs` runs `npm install` for the root and for every UI bundle that has a `package.json` (via Node's `child_process` with an explicit `cwd` — no `cd &&` shell chaining), then verifies `node_modules` landed everywhere it installed:
|
|
90
71
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
[ -f "$b/package.json" ] && ( cd "$b" && npm install )
|
|
94
|
-
done
|
|
72
|
+
```sh
|
|
73
|
+
node "<SKILL_DIR>/scripts/install-deps.mjs" "<dest>"
|
|
95
74
|
```
|
|
96
75
|
|
|
97
|
-
|
|
76
|
+
Substitute the literal `$DEST` value from Step 2 for `<dest>`. The script prints `OK: all dependencies installed.` and exits 0 on success; it exits non-zero with a listed summary of which install(s) failed otherwise. First-run install of the bundle is the heavy step; expect a short wait. If an install fails, surface it — don't hand off a half-installed project.
|
|
98
77
|
|
|
99
78
|
## Step 4: Confirm and hand off
|
|
100
79
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```sh
|
|
104
|
-
ls "$DEST" # sfdx-project.json, package.json, force-app/, scripts/, README.md ...
|
|
105
|
-
ls "$DEST"/force-app/main/default/uiBundles/*/node_modules >/dev/null && echo "bundle deps installed"
|
|
106
|
-
```
|
|
80
|
+
`install-deps.mjs` already prints a verification summary (root + each UI bundle's `node_modules`) as part of Step 3. To look around the generated project yourself, use your own file-listing/read tools rather than a shell `ls` — that works identically regardless of the underlying OS shell.
|
|
107
81
|
|
|
108
82
|
The project is now ready to develop and deploy. If there's a `README.md` in the template, take a look at it to see if there is any extra step or guidance for the user.
|
|
109
83
|
|
|
@@ -10,24 +10,46 @@
|
|
|
10
10
|
// — only the paths the template ships get replaced. The per-entry rmSync + renameSync is what
|
|
11
11
|
// guarantees the template's files win on conflict (including a file-vs-directory type mismatch).
|
|
12
12
|
// Requires Node ≥ 16.7 for rmSync.
|
|
13
|
+
//
|
|
14
|
+
// Always invoke via `node` (never as a bare executable) so this works on Windows cmd/PowerShell
|
|
15
|
+
// as well as macOS/Linux/Git Bash. Uses fs/path APIs only — no shell-out — so path separators and
|
|
16
|
+
// move semantics are correct on every OS.
|
|
13
17
|
|
|
14
18
|
import fs from "node:fs";
|
|
15
19
|
import path from "node:path";
|
|
20
|
+
import { pathToFileURL } from "node:url";
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
export function flattenProject(src, dest) {
|
|
23
|
+
if (!fs.existsSync(path.join(src, "sfdx-project.json"))) {
|
|
24
|
+
throw new Error("generated project has no sfdx-project.json: " + src);
|
|
25
|
+
}
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
for (const entry of fs.readdirSync(src)) {
|
|
28
|
+
const target = path.join(dest, entry);
|
|
29
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
30
|
+
fs.renameSync(path.join(src, entry), target);
|
|
31
|
+
}
|
|
22
32
|
}
|
|
23
33
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
function main() {
|
|
35
|
+
const [src, dest] = process.argv.slice(2);
|
|
36
|
+
|
|
37
|
+
if (!src || !dest) {
|
|
38
|
+
console.error("usage: node <skill_dir>/scripts/flatten-project.mjs <srcDir> <destDir>");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
flattenProject(src, dest);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error(err.message);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
27
48
|
}
|
|
28
49
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
// Only run as a CLI when invoked directly (not when imported by generate-project.mjs).
|
|
51
|
+
// pathToFileURL handles Windows drive letters/backslashes correctly (a manual
|
|
52
|
+
// `file://${path}` string would not).
|
|
53
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
54
|
+
main();
|
|
33
55
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Generate a `sf template generate project` starter and flatten it so the
|
|
3
|
+
// contents land directly at the target root (no `<name>/` wrapper subfolder).
|
|
4
|
+
//
|
|
5
|
+
// Usage: node <skill_dir>/scripts/generate-project.mjs <name> <dest> <template>
|
|
6
|
+
// <name> — project name passed to `sf template generate project --name`
|
|
7
|
+
// <dest> — target root directory the contents should land in
|
|
8
|
+
// (so sfdx-project.json sits at <dest>/sfdx-project.json)
|
|
9
|
+
// <template> — the `--template` flag value from the chosen framework reference
|
|
10
|
+
//
|
|
11
|
+
// Always invoke via `node` (never as a bare executable, and never wrap this
|
|
12
|
+
// in a bash/cmd/PowerShell script) so this works on Windows cmd/PowerShell
|
|
13
|
+
// as well as macOS/Linux/Git Bash. Pass <name>/<dest>/<template> as literal
|
|
14
|
+
// argv values — do not rely on shell variable assignment/interpolation
|
|
15
|
+
// (`$VAR` / `%VAR%` / `$env:VAR` differ per shell).
|
|
16
|
+
//
|
|
17
|
+
// Runs `sf` via spawnSync with shell:true so the platform's own shell
|
|
18
|
+
// resolves the CLI shim correctly (on Windows, globally-installed CLIs are
|
|
19
|
+
// usually `.cmd`/`.ps1` wrappers that spawn() cannot find without a shell).
|
|
20
|
+
//
|
|
21
|
+
// Exit 0 on success (project landed at <dest>).
|
|
22
|
+
// Exit 1 if `sf template generate project` fails, the generated project has
|
|
23
|
+
// no sfdx-project.json, or the flatten didn't result in a valid project root.
|
|
24
|
+
|
|
25
|
+
import fs from "node:fs";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { spawnSync } from "node:child_process";
|
|
28
|
+
import { flattenProject } from "./flatten-project.mjs";
|
|
29
|
+
|
|
30
|
+
const [name, dest, template] = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
function fail(message) {
|
|
33
|
+
console.error(message);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!name || !dest || !template) {
|
|
38
|
+
fail("usage: node <skill_dir>/scripts/generate-project.mjs <name> <dest> <template>");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
42
|
+
|
|
43
|
+
const result = spawnSync(
|
|
44
|
+
"sf",
|
|
45
|
+
["template", "generate", "project", "--name", name, "--template", template, "--output-dir", dest],
|
|
46
|
+
{ stdio: "inherit", shell: true },
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (result.error) {
|
|
50
|
+
fail(`ERROR: failed to run "sf template generate project": ${result.error.message}`);
|
|
51
|
+
}
|
|
52
|
+
if (result.status !== 0) {
|
|
53
|
+
process.exit(result.status ?? 1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const srcDir = path.join(dest, name);
|
|
57
|
+
|
|
58
|
+
if (!fs.existsSync(path.join(srcDir, "sfdx-project.json"))) {
|
|
59
|
+
fail(`ERROR: generated project has no sfdx-project.json: ${srcDir}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
flattenProject(srcDir, dest);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
fail(`ERROR: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Remove the now-empty (or leftover) generated subfolder.
|
|
69
|
+
fs.rmSync(srcDir, { recursive: true, force: true });
|
|
70
|
+
|
|
71
|
+
const destProjectFile = path.join(dest, "sfdx-project.json");
|
|
72
|
+
if (!fs.existsSync(destProjectFile)) {
|
|
73
|
+
fail(`FAILED: sfdx-project.json not found at ${destProjectFile} — flatten did not run correctly`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`OK: project root landed at ${dest} (${destProjectFile})`);
|
|
77
|
+
process.exit(0);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Install dependencies for a generated UI bundle starter project: the
|
|
3
|
+
// project root `package.json`, plus each `package.json` under
|
|
4
|
+
// force-app/main/default/uiBundles/*/ (the toolchain the preview server
|
|
5
|
+
// loads). Then verify node_modules landed everywhere it was installed.
|
|
6
|
+
//
|
|
7
|
+
// Usage: node <skill_dir>/scripts/install-deps.mjs <dest>
|
|
8
|
+
// <dest> — the project root (same value passed to generate-project.mjs)
|
|
9
|
+
//
|
|
10
|
+
// Always invoke via `node` (never as a bare executable, and never wrap this
|
|
11
|
+
// in a bash/cmd/PowerShell script) so this works on Windows cmd/PowerShell
|
|
12
|
+
// as well as macOS/Linux/Git Bash. Runs `npm install` via spawnSync with an
|
|
13
|
+
// explicit `cwd` (no `cd &&` subshell chaining) and shell:true so the
|
|
14
|
+
// platform's own shell resolves the `npm` CLI shim correctly.
|
|
15
|
+
//
|
|
16
|
+
// Exit 0 if every install succeeded (or there was nothing to install).
|
|
17
|
+
// Exit 1 with a summary of which installs failed — surface it, don't hand
|
|
18
|
+
// off a half-installed project.
|
|
19
|
+
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { spawnSync } from "node:child_process";
|
|
23
|
+
|
|
24
|
+
const [dest] = process.argv.slice(2);
|
|
25
|
+
|
|
26
|
+
if (!dest) {
|
|
27
|
+
console.error("usage: node <skill_dir>/scripts/install-deps.mjs <dest>");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function npmInstall(cwd) {
|
|
32
|
+
console.log(`Running "npm install" in ${cwd} ...`);
|
|
33
|
+
const result = spawnSync("npm", ["install"], { cwd, stdio: "inherit", shell: true });
|
|
34
|
+
if (result.error) {
|
|
35
|
+
return `${cwd}: ${result.error.message}`;
|
|
36
|
+
}
|
|
37
|
+
if (result.status !== 0) {
|
|
38
|
+
return `${cwd}: npm install exited with code ${result.status}`;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const failures = [];
|
|
44
|
+
|
|
45
|
+
// 1. Project root.
|
|
46
|
+
if (fs.existsSync(path.join(dest, "package.json"))) {
|
|
47
|
+
const failure = npmInstall(dest);
|
|
48
|
+
if (failure) failures.push(failure);
|
|
49
|
+
} else {
|
|
50
|
+
console.error(`ERROR: no package.json found at project root: ${dest}`);
|
|
51
|
+
failures.push(`${dest}: missing package.json`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 2. Each UI bundle.
|
|
55
|
+
const bundlesDir = path.join(dest, "force-app", "main", "default", "uiBundles");
|
|
56
|
+
const bundleDirs = fs.existsSync(bundlesDir)
|
|
57
|
+
? fs
|
|
58
|
+
.readdirSync(bundlesDir, { withFileTypes: true })
|
|
59
|
+
.filter((entry) => entry.isDirectory())
|
|
60
|
+
.map((entry) => path.join(bundlesDir, entry.name))
|
|
61
|
+
: [];
|
|
62
|
+
|
|
63
|
+
for (const bundleDir of bundleDirs) {
|
|
64
|
+
if (fs.existsSync(path.join(bundleDir, "package.json"))) {
|
|
65
|
+
const failure = npmInstall(bundleDir);
|
|
66
|
+
if (failure) failures.push(failure);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 3. Verify node_modules landed everywhere it was installed.
|
|
71
|
+
console.log("\nVerifying installs:");
|
|
72
|
+
let allInstalled = true;
|
|
73
|
+
if (fs.existsSync(path.join(dest, "package.json"))) {
|
|
74
|
+
const ok = fs.existsSync(path.join(dest, "node_modules"));
|
|
75
|
+
console.log(` ${ok ? "OK" : "MISSING"}: ${path.join(dest, "node_modules")}`);
|
|
76
|
+
allInstalled = allInstalled && ok;
|
|
77
|
+
}
|
|
78
|
+
for (const bundleDir of bundleDirs) {
|
|
79
|
+
if (fs.existsSync(path.join(bundleDir, "package.json"))) {
|
|
80
|
+
const ok = fs.existsSync(path.join(bundleDir, "node_modules"));
|
|
81
|
+
console.log(` ${ok ? "OK" : "MISSING"}: ${path.join(bundleDir, "node_modules")}`);
|
|
82
|
+
allInstalled = allInstalled && ok;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (failures.length > 0 || !allInstalled) {
|
|
87
|
+
console.error("\nFAILED: one or more installs did not complete:");
|
|
88
|
+
for (const failure of failures) {
|
|
89
|
+
console.error(` - ${failure}`);
|
|
90
|
+
}
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log("\nOK: all dependencies installed.");
|
|
95
|
+
process.exit(0);
|
|
@@ -13,6 +13,7 @@ metadata:
|
|
|
13
13
|
- "service-omni-base-settings-configure"
|
|
14
14
|
- "service-omni-channel-inventory-analyze"
|
|
15
15
|
- "service-omni-command-center-analyze"
|
|
16
|
+
- "service-omni-command-center-configure"
|
|
16
17
|
- "service-omni-permission-set-assign"
|
|
17
18
|
- "service-omni-presence-status-deploy"
|
|
18
19
|
- "service-omni-presence-user-config-deploy"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-omni-command-center-configure
|
|
3
|
+
description: "Use to enable Command Center for Service V2 and configure its supported supervisor controls through the OmniChannel Settings Metadata API while preserving unrelated settings. Requires explicit apply consent, refuses production customer orgs, and verifies the seeded V2 page and tab. TRIGGER when: enable Command Center V2, configure conversation monitoring, enable agent sneak peek, enable customer sneak peek, configure whisper messaging, or enable queues and skills actions. Do not use to assign supervisor permissions or configure classic OmniSupervisorConfig metadata."
|
|
4
|
+
allowed-tools: Bash Read Write Edit Grep Glob
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0"
|
|
7
|
+
domains: ["Service"]
|
|
8
|
+
minApiVersion: "69.0"
|
|
9
|
+
relatedSkills:
|
|
10
|
+
- "service-omni-base-settings-configure"
|
|
11
|
+
- "service-omni-channel-setup-coordinate"
|
|
12
|
+
- "service-omni-command-center-analyze"
|
|
13
|
+
- "service-omni-supervisor-config-deploy"
|
|
14
|
+
accessCheck:
|
|
15
|
+
- type: license
|
|
16
|
+
value: ServiceCloud
|
|
17
|
+
cliTools:
|
|
18
|
+
- tool: ["jq"]
|
|
19
|
+
semver: ">=1.6"
|
|
20
|
+
- tool: ["python3"]
|
|
21
|
+
semver: ">=3.8"
|
|
22
|
+
- tool: ["sf"]
|
|
23
|
+
semver: ">=2.139.6"
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# service-omni-command-center-configure
|
|
27
|
+
|
|
28
|
+
Enable Command Center for Service V2 through `Settings:OmniChannel` and optionally configure the five supervisor controls exposed by the same Metadata API contract. The writer retrieves the org's complete settings document, changes only requested elements, deploys that preserved document, retrieves it again, and verifies both the values and the platform-created `CommandCenterForServiceV2_L` page and V2 tab.
|
|
29
|
+
|
|
30
|
+
The skill fails closed with `platform_api_unavailable` when the retrieved settings document does not expose `enableCommandCenterForServiceV2`.
|
|
31
|
+
|
|
32
|
+
Run `service-omni-base-settings-configure` first so the Omni foundation is enabled. If the org does not support Command Center V2, use `service-omni-supervisor-config-deploy` for the classic supervisor configuration instead.
|
|
33
|
+
|
|
34
|
+
For an end-to-end setup, `service-omni-channel-setup-coordinate` invokes this skill only when `OMNI_COMMAND_CENTER_V2=1`; the coordinator's default supervisor path remains unchanged.
|
|
35
|
+
|
|
36
|
+
## Inputs
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bash scripts/configure-and-report.sh plan <org-alias> [options]
|
|
40
|
+
bash scripts/configure-and-report.sh run <org-alias> --apply [options]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
|
|
45
|
+
| Option | Metadata element | Values |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `--conversation-monitoring` | `enableConversationMonitoring` | `true` or `false` |
|
|
48
|
+
| `--agent-sneak-peek` | `enableAgentSneakPeek` | `true` or `false` |
|
|
49
|
+
| `--customer-sneak-peek` | `enableClientSneakPeek` | `true` or `false` |
|
|
50
|
+
| `--whisper-messaging` | `enableWhisperMessaging` | `true` or `false` |
|
|
51
|
+
| `--queues-and-skills` | `enableSkillsAndQueueActions` | `true` or `false` |
|
|
52
|
+
|
|
53
|
+
`enableCommandCenterForServiceV2=true` is always requested. Unspecified supervisor controls are preserved exactly as retrieved. The skill intentionally does not disable V2 because disabling an org-level supervisor experience is a materially different operation.
|
|
54
|
+
|
|
55
|
+
## Safety
|
|
56
|
+
|
|
57
|
+
- `plan` is read-only and never deploys.
|
|
58
|
+
- `run` requires the literal `--apply` flag before any mutation.
|
|
59
|
+
- Writes are allowed only when `IsSandbox=true`, `TrialExpirationDate` is non-null, or `OrganizationType` is `Developer Edition` or `Base Edition`. There is no production override.
|
|
60
|
+
- `Settings` is a whole-document Metadata API type. Never deploy a partial or hardcoded `OmniChannel.settings-meta.xml`; doing so can reset unrelated Omni settings.
|
|
61
|
+
- The target org must have Enhanced Omni-Channel and the Command Center for Service V2 release gater. The API field is also permission-gated by `Customize Application`.
|
|
62
|
+
|
|
63
|
+
## Behavior
|
|
64
|
+
|
|
65
|
+
1. Authenticate and retrieve `Settings:OmniChannel` at API v66.
|
|
66
|
+
2. Confirm the V2 field is present. If it is absent, return `blocked` with `reason_code=platform_api_unavailable`; do not attempt a deploy.
|
|
67
|
+
3. Build a requested-value set containing V2=`true` plus only the optional controls explicitly supplied by the caller.
|
|
68
|
+
4. In `plan`, return `action_needed` or `reused` without writing.
|
|
69
|
+
5. In `run`, enforce `--apply` and the non-production guard, mutate a private copy of the retrieved document, and deploy it.
|
|
70
|
+
6. Retrieve the settings again and require every requested value to match.
|
|
71
|
+
7. Require both the seeded `FlexiPage` (`CommandCenterForServiceV2_L`) and V2 `TabDefinition` to be observable. Missing or unreadable provisioning evidence returns `blocked`; the skill never guesses.
|
|
72
|
+
|
|
73
|
+
The platform's ON-transition hook is idempotent: it creates missing profile tab configuration and seeds the baseline FlexiPage only when needed. Existing page customizations are not overwritten. If the preference is already true but its seed artifacts are missing, the skill returns `seed_incomplete`; it does not force a destructive OFF→ON cycle.
|
|
74
|
+
|
|
75
|
+
## Output contract
|
|
76
|
+
|
|
77
|
+
The script emits one JSON object with:
|
|
78
|
+
|
|
79
|
+
- `status`: `configured`, `reused`, `action_needed`, or `blocked`
|
|
80
|
+
- `reason_code`: a stable reason such as `changes_required`, `already_configured`, `platform_api_unavailable`, `unsafe_target`, `deploy_failed`, `verification_failed`, or `seed_incomplete`
|
|
81
|
+
- `requested`, `before`, and `after`: setting values, with presence retained in the snapshots
|
|
82
|
+
- `safe_to_write`, `deploy_id`, and `verification`
|
|
83
|
+
- `manual_actions`: permission assignment and any required follow-up
|
|
84
|
+
- `blocking_issue`: populated only when blocked
|
|
85
|
+
|
|
86
|
+
Enabling the org preference does not grant user access. Assign a permission set containing `CommandCenterForServiceUser` to each intended supervisor, then run `service-omni-command-center-analyze <org> <supervisor>` to verify end-to-end readiness.
|
|
87
|
+
|
|
88
|
+
## References
|
|
89
|
+
|
|
90
|
+
| File | When to read |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `references/api-notes.md` | Metadata names, platform gates, seed behavior, and known limitations |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Command Center for Service V2 API notes
|
|
2
|
+
|
|
3
|
+
## Metadata contract
|
|
4
|
+
|
|
5
|
+
Core work item `W-24039822` and Core PR `#16874` expose these fields on `Settings:OmniChannel`:
|
|
6
|
+
|
|
7
|
+
| Metadata field | Product control |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `enableCommandCenterForServiceV2` | Command Center for Service V2 |
|
|
10
|
+
| `enableConversationMonitoring` | Conversation monitoring |
|
|
11
|
+
| `enableAgentSneakPeek` | Agent sneak peek |
|
|
12
|
+
| `enableClientSneakPeek` | Customer sneak peek |
|
|
13
|
+
| `enableWhisperMessaging` | Whisper messaging |
|
|
14
|
+
| `enableSkillsAndQueueActions` | Queues and skills actions |
|
|
15
|
+
|
|
16
|
+
The V2 preference is Metadata API writable only when the target release contains that contract and the `OmniChannel.commandCenterForServiceV2Available` access check passes. That access check requires the feature gater and Enhanced Omni-Channel. Standard Omni orgs on the EOL extension cannot enable V2.
|
|
17
|
+
|
|
18
|
+
## ON-transition side effects
|
|
19
|
+
|
|
20
|
+
Changing `enableCommandCenterForServiceV2` from false to true invokes the existing `CommandCenterForServiceV2OrgPreference` hook. The hook:
|
|
21
|
+
|
|
22
|
+
1. inserts missing profile tab configurations for the V2 tab;
|
|
23
|
+
2. checks for `FlexiPage.DeveloperName='CommandCenterForServiceV2_L'`;
|
|
24
|
+
3. clones the platform seed only when that page is absent.
|
|
25
|
+
|
|
26
|
+
Disabling the preference does not delete the page. Re-enabling preserves an existing page. This skill enables but does not disable V2.
|
|
27
|
+
|
|
28
|
+
## Verification signals
|
|
29
|
+
|
|
30
|
+
The writer verifies the settings by a fresh Metadata API retrieve and verifies provisioning through:
|
|
31
|
+
|
|
32
|
+
```sql
|
|
33
|
+
SELECT Id FROM FlexiPage WHERE DeveloperName='CommandCenterForServiceV2_L'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
using Tooling API, and:
|
|
37
|
+
|
|
38
|
+
```sql
|
|
39
|
+
SELECT Name FROM TabDefinition WHERE Name='standard-commandcenterforservicev2'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
using the data API. Query errors remain `unknown` and block a successful write claim.
|
|
43
|
+
|
|
44
|
+
## User access
|
|
45
|
+
|
|
46
|
+
The org preference and its seed artifacts establish org-level readiness only. A supervisor also needs a permission set with `PermissionsCommandCenterForServiceUser=true`. This skill reports that follow-up but does not create users or permission sets.
|
|
47
|
+
|
|
48
|
+
## Whole-document requirement
|
|
49
|
+
|
|
50
|
+
Salesforce Settings metadata is deployed as a complete document. The implementation retrieves the current document and updates it in place. Do not replace this approach with a static template: a static template can silently drop existing Omni settings that are outside this skill's scope.
|