@salesforce/afv-skills 1.67.0 → 1.68.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 (118) hide show
  1. package/README.md +55 -5
  2. package/package.json +1 -1
  3. package/skills/agentforce-offline-experimentation-run/SKILL.md +14 -22
  4. package/skills/agentforce-offline-experimentation-run/scripts/bt_compare.py +81 -0
  5. package/skills/agentforce-offline-experimentation-run/scripts/bt_fetch.py +358 -0
  6. package/skills/agentforce-offline-experimentation-run/scripts/bt_patch_agent.py +110 -0
  7. package/skills/agentforce-offline-experimentation-run/scripts/btlib/__init__.py +34 -0
  8. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentpatch.py +483 -0
  9. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentsrc.py +565 -0
  10. package/skills/agentforce-offline-experimentation-run/scripts/btlib/cache.py +95 -0
  11. package/skills/agentforce-offline-experimentation-run/scripts/btlib/compare.py +617 -0
  12. package/skills/agentforce-offline-experimentation-run/scripts/btlib/fetch.py +1012 -0
  13. package/skills/agentforce-offline-experimentation-run/scripts/btlib/judge.py +148 -0
  14. package/skills/agentforce-offline-experimentation-run/scripts/btlib/messages.py +92 -0
  15. package/skills/agentforce-offline-experimentation-run/scripts/btlib/patch.py +327 -0
  16. package/skills/agentforce-offline-experimentation-run/scripts/btlib/redact.py +40 -0
  17. package/skills/agentforce-offline-experimentation-run/scripts/btlib/results.py +288 -0
  18. package/skills/agentforce-offline-experimentation-run/scripts/btlib/scoring.py +340 -0
  19. package/skills/agentforce-offline-experimentation-run/scripts/btlib/sfap.py +238 -0
  20. package/skills/agentforce-offline-experimentation-run/scripts/btlib/splits.py +136 -0
  21. package/skills/agentforce-offline-experimentation-run/scripts/btlib/stdm.py +98 -0
  22. package/skills/agentforce-offline-experimentation-run/scripts/btlib/tokens.py +173 -0
  23. package/skills/agentforce-offline-experimentation-run/scripts/btlib/units.py +199 -0
  24. package/skills/agentforce-offline-experimentation-run/scripts/btlib/versions.py +194 -0
  25. package/skills/agentforce-offline-experimentation-run/scripts/build_report.py +366 -378
  26. package/skills/agentforce-offline-experimentation-run/scripts/resolve-token.sh +14 -4
  27. package/skills/agentforce-offline-experimentation-run/scripts/sfap_replay.py +472 -796
  28. package/skills/dx-lifecycle-center/SKILL.md +5 -2
  29. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/connect-connected.json +65 -0
  30. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/schema.json +32 -0
  31. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/connect-sign-in.json +57 -0
  32. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/schema.json +21 -0
  33. package/skills/dx-lifecycle-center/examples/workflows.md +20 -6
  34. package/skills/dx-lifecycle-center/references/connect-org.md +21 -2
  35. package/skills/dx-lifecycle-center/references/deploy.md +2 -2
  36. package/skills/dx-lifecycle-center/references/list-orgs.md +1 -1
  37. package/skills/dx-lifecycle-center/scripts/card-policy.jq +71 -0
  38. package/skills/dx-lifecycle-center/scripts/fill-widget.jq +29 -0
  39. package/skills/dx-lifecycle-center/scripts/widget.sh +28 -0
  40. package/skills/dx-org-devhub-configure/SKILL.md +85 -84
  41. package/skills/dx-org-devhub-configure/examples/status-output.md +25 -2
  42. package/skills/dx-org-devhub-configure/scripts/devhub.sh +265 -140
  43. package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +100 -15
  44. package/skills/dx-packaging-move-to-2gp-migrate/SKILL.md +89 -0
  45. package/skills/dx-packaging-move-to-2gp-migrate/references/api-operations.md +164 -0
  46. package/skills/dx-scratch-def-configure/SKILL.md +163 -0
  47. package/skills/dx-scratch-def-configure/examples/confirm-card.md +53 -0
  48. package/skills/dx-scratch-def-configure/examples/report-recipes.md +100 -0
  49. package/skills/dx-scratch-def-configure/references/features.json +3270 -0
  50. package/skills/dx-scratch-def-configure/references/project-scratch-def.schema.json +1841 -0
  51. package/skills/dx-scratch-def-configure/references/settings-map.json +682 -0
  52. package/skills/dx-scratch-def-configure/scripts/lib_scratch_def.py +1306 -0
  53. package/skills/dx-scratch-def-configure/scripts/requirements.txt +3 -0
  54. package/skills/dx-scratch-def-configure/scripts/scrape_config_values.py +848 -0
  55. package/skills/education-cloud-domain-configure/SKILL.md +1 -1
  56. package/skills/education-cloud-multi-campus-configure/SKILL.md +1 -1
  57. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +1 -1
  58. package/skills/experience-design-validate/SKILL.md +1 -1
  59. package/skills/experience-search-coordinate/SKILL.md +18 -12
  60. package/skills/experience-search-coordinate/references/content-route.md +79 -1
  61. package/skills/field-service-data-capture-migrate/SKILL.md +1 -1
  62. package/skills/platform-apex-generate/SKILL.md +14 -11
  63. package/skills/platform-apex-test-generate/SKILL.md +2 -1
  64. package/skills/platform-datamask-run/SKILL.md +52 -71
  65. package/skills/platform-datamask-run/references/api-surface.md +10 -4
  66. package/skills/platform-datamask-run/references/policy-authoring.md +56 -7
  67. package/skills/platform-datamask-run/references/run-and-abort.md +17 -10
  68. package/skills/platform-datamask-run/scripts/poll-job.sh +15 -25
  69. package/skills/platform-dataspace-access-configure/SKILL.md +19 -1
  70. package/skills/platform-metadata-discovery-get/SKILL.md +185 -0
  71. package/skills/platform-metadata-discovery-get/references/api-map.md +25 -0
  72. package/skills/platform-metadata-discovery-get/references/h360-routes.md +30 -0
  73. package/skills/platform-metadata-discovery-get/references/scoped-soql.md +52 -0
  74. package/skills/platform-metadata-grounding-get/SKILL.md +170 -0
  75. package/skills/platform-policy-rule-generate/SKILL.md +84 -232
  76. package/skills/platform-policy-rule-generate/references/condition-model.md +47 -0
  77. package/skills/platform-policy-rule-generate/references/condition-templates.md +89 -0
  78. package/skills/platform-policy-rule-generate/references/conjunction-compiler.md +25 -0
  79. package/skills/platform-policy-rule-generate/references/conjunction-expression.md +22 -0
  80. package/skills/platform-policy-rule-generate/references/consumer-all.md +9 -0
  81. package/skills/platform-policy-rule-generate/references/consumer-datacloud-ui.md +91 -0
  82. package/skills/platform-policy-rule-generate/references/deploy-errors.md +24 -36
  83. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/package.xml +12 -0
  84. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitionSets/ExistsJoinRLS.policyRuleDefinitionSet +6 -0
  85. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitions/ExistsJoinRLS_Rule_1.policyRuleDefinition +91 -0
  86. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/package.xml +12 -0
  87. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitionSets/FieldReadDeny.policyRuleDefinitionSet +6 -0
  88. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitions/FieldReadDeny_Rule_1.policyRuleDefinition +72 -0
  89. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/package.xml +12 -0
  90. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitionSets/LastCharactersFieldMasking.policyRuleDefinitionSet +6 -0
  91. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitions/LastCharactersFieldMasking_Rule_1.policyRuleDefinition +77 -0
  92. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/package.xml +12 -0
  93. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitionSets/PrincipalFieldMatchRLS.policyRuleDefinitionSet +6 -0
  94. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitions/PrincipalFieldMatchRLS_Rule_1.policyRuleDefinition +77 -0
  95. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/package.xml +12 -0
  96. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitionSets/TaggedObjectAccess.policyRuleDefinitionSet +4 -0
  97. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitions/TaggedObjectAccess_Rule_1.policyRuleDefinition +65 -0
  98. package/skills/platform-policy-rule-generate/references/headless-transport.md +87 -0
  99. package/skills/platform-policy-rule-generate/references/policy-schema-full.md +17 -10
  100. package/skills/platform-policy-rule-generate/references/policy-shapes.md +74 -0
  101. package/skills/platform-policy-rule-generate/references/principal-expression.md +31 -0
  102. package/skills/platform-policy-rule-generate/references/reference-resolution.md +51 -0
  103. package/skills/platform-policy-rule-generate/references/resource-expression.md +48 -0
  104. package/skills/platform-policy-rule-generate/references/runtime-context.md +9 -0
  105. package/skills/platform-policy-rule-generate/references/templates-access.md +11 -9
  106. package/skills/platform-policy-rule-generate/references/templates-advanced.md +4 -2
  107. package/skills/platform-policy-rule-generate/references/templates-record.md +37 -22
  108. package/skills/platform-policy-rule-generate/references/templates-transform.md +10 -8
  109. package/skills/platform-policy-rule-generate/references/templates.md +2 -2
  110. package/skills/platform-policy-rule-generate/references/ui-compatibility.md +35 -17
  111. package/skills/platform-report-generate/SKILL.md +9 -4
  112. package/skills/platform-report-generate/references/chart-types.md +26 -2
  113. package/skills/platform-report-generate/references/column-names.md +43 -0
  114. package/skills/platform-report-generate/references/errors-and-troubleshooting.md +1 -1
  115. package/skills/platform-report-generate/references/verification-checklist.md +10 -2
  116. package/skills/service-digital-engagement-channel-configure/SKILL.md +7 -5
  117. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +33 -0
  118. package/skills/service-digital-engagement-channel-configure/references/channel_settings.md +110 -14
@@ -16,13 +16,28 @@ printf '%s\n' "$*" >> "$SF_STUB_LOG"
16
16
 
17
17
  case "$*" in
18
18
  "config get target-org --json")
19
- printf '%s\n' '{"status":0,"result":[{"value":"default-org"}]}'
19
+ if [ "${SF_TEST_NO_DEFAULT:-0}" = "1" ]; then
20
+ printf '%s\n' '{"status":0,"result":[]}'
21
+ else
22
+ printf '%s\n' '{"status":0,"result":[{"value":"default-org"}]}'
23
+ fi
20
24
  ;;
21
25
  "config get target-dev-hub --json")
22
- printf '%s\n' '{"status":0,"result":[{"value":"default-devhub"}]}'
26
+ if [ "${SF_TEST_NO_DEFAULT:-0}" = "1" ]; then
27
+ printf '%s\n' '{"status":0,"result":[]}'
28
+ else
29
+ printf '%s\n' '{"status":0,"result":[{"value":"default-devhub"}]}'
30
+ fi
23
31
  ;;
24
- org\ login\ web*)
25
- printf '%s\n' '{"status":0,"result":{"username":"logged-in@example.com"}}'
32
+ "org list --json")
33
+ if [ "${SF_TEST_HANG:-0}" = "1" ]; then
34
+ sleep 60
35
+ fi
36
+ if [ "${SF_TEST_NO_ORGS:-0}" = "1" ]; then
37
+ printf '%s\n' '{"status":0,"result":{"nonScratchOrgs":[],"scratchOrgs":[]}}'
38
+ else
39
+ printf '%s\n' '{"status":0,"result":{"nonScratchOrgs":[{"alias":"my-org","username":"a@b.com","connectedStatus":"Connected","isDefaultUsername":true}],"scratchOrgs":[]}}'
40
+ fi
26
41
  ;;
27
42
  "data query --query SELECT COUNT() FROM ScratchOrgInfo"*)
28
43
  if [ "${SF_TEST_DEVHUB_ENABLED:-0}" = "1" ]; then
@@ -32,12 +47,18 @@ case "$*" in
32
47
  exit 1
33
48
  fi
34
49
  ;;
50
+ "data query --query SELECT OrganizationType, IsSandbox FROM Organization"*)
51
+ printf '%s\n' "{\"status\":0,\"result\":{\"records\":[{\"OrganizationType\":\"Developer Edition\",\"IsSandbox\":${SF_TEST_SANDBOX:-false}}]}}"
52
+ ;;
53
+ "api request rest /services/data/"*"/tooling/sobjects/DevHubSettings/DevHub"*)
54
+ printf '%s\n' '{"Id":"DevHub","FullName":"DevHub","Metadata":{"enableScratchOrgManagementPref":true,"enablePackaging2":false,"enableScratchOrgSnapshotPref":true,"enableShapeExportPref":false}}'
55
+ ;;
35
56
  "org list limits"*)
36
57
  if [ "${SF_TEST_LIMITS_FAIL:-0}" = "1" ]; then
37
58
  printf '%s\n' '{"status":1,"message":"limits unavailable"}'
38
59
  exit 1
39
60
  fi
40
- printf '%s\n' '{"status":0,"result":[{"name":"ActiveScratchOrgs","remaining":3,"max":3},{"name":"DailyScratchOrgs","remaining":6,"max":6}]}'
61
+ printf '%s\n' "{\"status\":0,\"result\":[{\"name\":\"ActiveScratchOrgs\",\"remaining\":${SF_TEST_ACTIVE_REM:-3},\"max\":${SF_TEST_ACTIVE_MAX:-3}},{\"name\":\"DailyScratchOrgs\",\"remaining\":${SF_TEST_DAILY_REM:-6},\"max\":${SF_TEST_DAILY_MAX:-6}}]}"
41
62
  ;;
42
63
  "org display"*)
43
64
  printf '%s\n' '{"status":0,"result":{"id":"00D000000000001","username":"admin@example.com","instanceUrl":"https://example.my.salesforce.com"}}'
@@ -79,7 +100,7 @@ check "reject disabling the master switch" 2 "cannot be set to false" \
79
100
  "$SCRIPT" explicit-org --pref enableScratchOrgManagementPref=false
80
101
 
81
102
  check "warn for scratch-management apply" 0 "IRREVERSIBLE" \
82
- "$SCRIPT" explicit-org --scratch-management --apply
103
+ env SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT" explicit-org --scratch-management --apply
83
104
 
84
105
  check "propagate status allocation failure" 1 "Could not read org limits" \
85
106
  env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_LIMITS_FAIL=1 "$SCRIPT" explicit-org
@@ -87,23 +108,87 @@ check "propagate status allocation failure" 1 "Could not read org limits" \
87
108
  check "require explicit target for apply" 2 "explicit org" \
88
109
  "$SCRIPT" --enable --apply
89
110
 
90
- check "reject non-Salesforce login origin" 2 "Salesforce hostname" \
91
- "$SCRIPT" explicit-org --instance-url https://attacker.example --login
111
+ # --- new: read current DevHubSettings preferences ---
112
+ check "show-settings renders master pref ON" 0 "enableScratchOrgManagementPref" \
113
+ env SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT" explicit-org --show-settings
114
+ check "show-settings renders packaging OFF" 0 "enablePackaging2 OFF" \
115
+ env SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT" explicit-org --show-settings
92
116
 
93
- check "login-only exits after authentication" 0 "Authenticated" \
117
+ # --- new: pre-flight allocation thresholds ---
118
+ check "threshold WARN under 2 remaining" 0 "WARN" \
119
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=1 SF_TEST_ACTIVE_MAX=3 "$SCRIPT" explicit-org --allocation
120
+ check "threshold NOTE above 80 percent" 0 "usage at" \
121
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=0 SF_TEST_ACTIVE_MAX=3 "$SCRIPT" explicit-org --allocation
122
+
123
+ # --- new: sandbox refuses enablement, before any deploy ---
124
+ : > "$LOG_FILE"
125
+ sandbox_out="$(env SF_TEST_DEVHUB_ENABLED=0 SF_TEST_SANDBOX=true "$SCRIPT" explicit-org --scratch-management --apply 2>&1)"
126
+ sandbox_rc=$?
127
+ if [ "$sandbox_rc" -eq 1 ] && printf '%s' "$sandbox_out" | grep -qi "sandbox" && ! grep -Fq "project deploy start" "$LOG_FILE"; then
128
+ pass=$((pass + 1)); printf 'PASS: sandbox refuses enablement without deploying\n'
129
+ else
130
+ fail=$((fail + 1)); printf 'FAIL: sandbox refuses enablement (exit %s)\n%s\n' "$sandbox_rc" "$sandbox_out"
131
+ fi
132
+
133
+ # --- new: org discovery when no default is set ---
134
+ check "org discovery lists authenticated orgs" 2 "my-org" \
135
+ env SF_TEST_NO_DEFAULT=1 SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT"
136
+
137
+ check "list-orgs mode lists authenticated orgs" 0 "my-org" \
138
+ "$SCRIPT" --list-orgs
139
+
140
+ # --- removed: login flags are now unknown options ---
141
+ check "login flag rejected" 2 "Unknown option" \
94
142
  "$SCRIPT" explicit-org --login
95
- if grep -Fq "data query" "$LOG_FILE"; then
96
- fail=$((fail + 1))
97
- printf 'FAIL: login-only queried org status\n'
143
+ check "instance-url flag rejected" 2 "Unknown option" \
144
+ "$SCRIPT" explicit-org --instance-url https://x.my.salesforce.com
145
+
146
+ # --- new: show-settings refuses when Dev Hub is OFF ---
147
+ check "show-settings refuses when Dev Hub off" 1 "no DevHubSettings to read" \
148
+ env SF_TEST_DEVHUB_ENABLED=0 "$SCRIPT" explicit-org --show-settings
149
+
150
+ # --- new: daily-limit NOTE threshold (only active was covered before) ---
151
+ check "threshold NOTE daily above 80 percent" 0 "Daily scratch org usage at" \
152
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_DAILY_REM=1 SF_TEST_DAILY_MAX=6 "$SCRIPT" explicit-org --allocation
153
+
154
+ # --- new: list-orgs with no authenticated orgs ---
155
+ check "list-orgs reports none authenticated" 0 "No orgs are authenticated" \
156
+ env SF_TEST_NO_ORGS=1 "$SCRIPT" --list-orgs
157
+
158
+ # A hung CLI must not hold the caller for the full stub sleep.
159
+ hang_start=$(date +%s)
160
+ hang_out="$(env SF_TEST_HANG=1 "$SCRIPT" --list-orgs 2>&1)"
161
+ hang_rc=$?
162
+ hang_elapsed=$(( $(date +%s) - hang_start ))
163
+ if [ "$hang_rc" -eq 1 ] && [ "$hang_elapsed" -lt 35 ] && printf '%s' "$hang_out" | grep -Fq "Could not list authenticated orgs"; then
164
+ pass=$((pass + 1)); printf 'PASS: list-orgs bounds a hung sf org list (%ss)\n' "$hang_elapsed"
98
165
  else
99
- pass=$((pass + 1))
100
- printf 'PASS: login-only skipped org status\n'
166
+ fail=$((fail + 1)); printf 'FAIL: list-orgs bounds a hung sf org list (exit %s, %ss)\n%s\n' "$hang_rc" "$hang_elapsed" "$hang_out"
101
167
  fi
102
168
 
169
+ # --- new: JSON fidelity for the added fields ---
170
+ check "status JSON reports edition" 0 "\"edition\": \"Developer Edition\"" \
171
+ env SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT" explicit-org --json
172
+ check "status JSON reports isSandbox false (not null) for non-sandbox" 0 "\"isSandbox\": false" \
173
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_SANDBOX=false "$SCRIPT" explicit-org --json
174
+ check "status JSON reports isSandbox true for sandbox" 0 "\"isSandbox\": true" \
175
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_SANDBOX=true "$SCRIPT" explicit-org --json
176
+ check "allocation JSON emits warnings array near limit" 0 "\"warnings\"" \
177
+ env SF_TEST_DEVHUB_ENABLED=1 SF_TEST_ACTIVE_REM=1 SF_TEST_ACTIVE_MAX=3 "$SCRIPT" explicit-org --allocation --json
178
+ check "show-settings JSON emits settings map" 0 "enableScratchOrgSnapshotPref" \
179
+ env SF_TEST_DEVHUB_ENABLED=1 "$SCRIPT" explicit-org --show-settings --json
180
+ check "list-orgs JSON emits normalized array" 0 "\"isDefault\"" \
181
+ "$SCRIPT" --list-orgs --json
182
+
183
+ # --- new: a not-enabled sandbox is flagged as ineligible in status ---
184
+ check "status flags sandbox as unable to host Dev Hub" 0 "cannot host Dev Hub" \
185
+ env SF_TEST_DEVHUB_ENABLED=0 SF_TEST_SANDBOX=true "$SCRIPT" explicit-org
186
+
187
+ # --- safety: cleanup trap treats TMPDIR content as data ---
103
188
  unsafe_tmp="$WORK_DIR/unsafe'; touch $MARKER; #"
104
189
  mkdir -p "$unsafe_tmp"
105
190
  check "cleanup trap does not execute TMPDIR content" 0 "Dry run passed" \
106
- env TMPDIR="$unsafe_tmp" "$SCRIPT" explicit-org --packaging
191
+ env SF_TEST_DEVHUB_ENABLED=1 TMPDIR="$unsafe_tmp" "$SCRIPT" explicit-org --packaging
107
192
  if [ -e "$MARKER" ]; then
108
193
  fail=$((fail + 1))
109
194
  printf 'FAIL: cleanup trap executed TMPDIR content\n'
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: dx-packaging-move-to-2gp-migrate
3
+ description: "Use this skill when users want to finalize the irreversible, one-way Move-to-2GP cutover for a converted 1GP managed package — afterward, new major/minor 1GP versions can NEVER be created. Also use when an ISV admin asks to move a 1GP package to 2GP development. TRIGGER when: the user asks to move, finalize, or complete the move of a converted 1GP managed package to 2GP development, asks how to move a package to 2GP, or asks whether their converted package is eligible to move to 2GP. DO NOT TRIGGER for: converting a 1GP package to 2GP in the first place, creating or promoting 2GP package versions, packaging UI bundles (use experience-ui-bundle-2gp-deploy), enabling Dev Hub (use dx-org-devhub-configure), or post-install configuration (use dx-pkg-post-install-configure)."
4
+ metadata:
5
+ relatedSkills:
6
+ - dx-org-devhub-configure
7
+ - dx-pkg-post-install-configure
8
+ - experience-ui-bundle-2gp-deploy
9
+ version: "1.0"
10
+ accessCheck: "UserPermissions.CreatePackaging"
11
+ cliTools:
12
+ - tool:
13
+ - "sf"
14
+ semver: ">=2.0.0"
15
+ domains:
16
+ - "Developer Experience"
17
+ ---
18
+
19
+
20
+ # Move to 2GP Development
21
+
22
+ ## When to Use This Skill
23
+
24
+ Finalize the irreversible, one-way Move-to-2GP cutover for a converted 1GP managed package — afterward, new major/minor 1GP versions can NEVER be created. Use when an ISV admin asks to move a 1GP package to 2GP development. The agent dispatches the finalize directly via the packaging Connect API (POST /connect/packaging/package/{packageId}/finalize-move-to-2gp, shipped 266) after clearing the eligibility + conversion/subscriber-migration-testing gates and obtaining the three explicit affirmations the endpoint requires; it then wire-verifies the result against PackageConversion.EndDate (read-only Tooling exposure, shipped 264).
25
+
26
+ ## Workflow
27
+
28
+ ---
29
+ BACKEND / VERSIONING MECHANICS (relocated from the discover card — describe-only, never shown on the card):
30
+ - FINALIZE DISPATCH (266+): the agent-dispatchable path is the packaging Connect API POST /services/data/v69.0/connect/packaging/package/{packageId}/finalize-move-to-2gp (operationId finalizeMoveTo2gp), which runs against the 1GP DE org. The endpoint enforces the CreatePackaging edit-access gate, requires all three affirmation flags true, and verifies the {packageId} in the URL matches the package the org is currently converting — a mismatch returns 400. On success it finalizes the conversion, after which PackageConversion.EndDate is set (observable via verify-finalize-on-packaging-org). It performs the same finalize action that was previously available only through the Setup UI's Move-to-2GP dialog.
31
+ - PRE-266 HISTORY / FALLBACK: before 266 no public agent-dispatchable API existed — finalize was available only as a Setup-page action the user completed in the browser, with no stable programmatic contract. The fallback delivers the user to the package's Setup detail page at `/udd/AllPackage/viewAllPackage.apexp` (any authenticated browser session to the packaging org reaches it), which hosts the "Move to Second-Generation Managed Packaging" dialog and its Proceed action. This remains the fallback for orgs on a pre-266 release.
32
+ - CANNOT-CREATE BOUNDARY, MECHANICS: after finalize, new major/minor 1GP versions cannot be created — neither via `sf package1 version create` nor via the major/minor upload flow on viewAllPackage.apexp; all new major/minor innovation must use 2GP via `sf package version create`. Customers running on prior 1GP versions are unaffected.
33
+ - PATCH EXCEPTION (surface conversationally only when the user asks e.g. "can I still cut a patch?"): PATCH versions of major.minor versions that existed BEFORE finalize remain permitted, to hotfix 1GP subscribers not yet migrated to 2GP. This exception is intentionally NOT part of the affirmation prompt the user confirms (the Setup dialog uses the same headline framing) — never put it in the affirmation.
34
+ - ELIGIBILITY GATE (3-part proactive pre-check, two-org query): (a) the 1GP package's highest Released major.minor version, queried from the 1GP DE org via MetadataPackageVersion; (b) a corresponding 2GP-converted Package2Version at the same major.minor on DevHub, AND that 2GP version is Released; (c) no native 2GP version exists yet on DevHub (its presence means Move-to-2GP already happened — early exit). Parts (b)/(c) are the DevHub-side pre-check: run them when DevHub is authenticated to give the user a clear up-front answer; if (a) or (b) fails, surface what's missing + the fix (typically promote the converted 2GP version to Released). When DevHub is unavailable, this proactive check is skipped and the finalize endpoint enforces the same eligibility server-side (→ 400 on mismatch). DevHub eligibility queries hit the Package2 / Package2Version 0Ho-prefix entity.
35
+ - PRE-FLIGHT (mandatory): Salesforce docs state "Before you complete your move to 2GP package development, it's critical that you thoroughly test package conversions and subscriber migrations first." Never invoke the manual step without explicit user affirmation that conversion + subscriber-migration testing is complete.
36
+ - RELEASE HISTORY (both milestones shipped): 264 exposed the PackageConversion object read-only via the Tooling API (available when packaging is enabled for the org), lighting up verify-finalize-on-packaging-org as an EndDate-based wire-verify. 266 shipped the Connect API finalize endpoint POST /services/data/v69.0/connect/packaging/package/{packageId}/finalize-move-to-2gp (operationId finalizeMoveTo2gp), driven by the 1GP MetadataPackage Id (033-prefix) with the three affirmation flags in the request body; finalize-move-to-2gp dispatches invocation.kind: rest, is status: implemented, and the skill is now fully agent-driveable end-to-end. The manual browser fallback path is retained only as a pre-266 fallback.
37
+ - WIRE-VERIFICATION (264+): the canonical post-finalize signal is PackageConversion.EndDate (non-null) on the 1GP DE org, queryable via the read-only Tooling exposure shipped in 264. The finalize endpoint's own response also returns finalizedAt + conversionId directly. Move-to-2GP does NOT auto-create a native (non-converted) Package2Version on DevHub — native versions are created later by a separate user-driven `sf package version create`, so their absence immediately post-finalize is expected, not a failure signal (i.e. there is no Package2Version-based wire-verify; EndDate is the reliable signal). verify-finalize-by-user-confirmation remains available as an optional human cross-check but is no longer the only verification surface.
38
+ - ORG REACHABILITY (auth mechanism is agent's choice, not `sf`-specific): only the 1GP DE (packaging) org is genuinely required — it backs the 266 Connect finalize endpoint, the read-only PackageConversion wire-verify (264), the 1GP-side eligibility query (MetadataPackageVersion), and the browser Setup page for the pre-266 fallback. Reachability can come from an `sf` alias OR any valid bearer token for the org (raw REST); the skill is not coupled to the `sf` CLI. The DevHub org (Package2 / Package2Version) is OPTIONAL — it only enables the proactive eligibility pre-check; when it is absent the finalize endpoint still validates eligibility server-side (a not-yet-converted/not-promoted package → 400), so the skill can proceed DevHub-less. This also sidesteps the multi-org-auth burden of skills that hard-require two authenticated orgs.
39
+
40
+ ## Critical Constraints
41
+
42
+ **Preconditions:**
43
+
44
+ - REQUIRED: the 1GP DE (packaging) org must be reachable with valid credentials. This is the one org the finalize path needs — an `sf` alias is the convenient way to authenticate, but the skill is NOT coupled to the `sf` CLI: any caller that can present a valid bearer token for this org (e.g. a raw REST call) works equally. The 1GP DE org hosts MetadataPackageVersion (the authoritative highest-Released 1GP version for the eligibility gate), is the org the finalize Connect API endpoint (266) runs against, hosts the read-only PackageConversion Tooling exposure (264) the wire-verify queries, and is the org the pre-266 manual browser fallback opens. (check: `PackagingOrgAuthenticated`)
45
+ - OPTIONAL (recommended): authenticating the DevHub org lets the agent proactively pre-check eligibility before dispatching finalize — the converted 2GP Package2Version at the matching major.minor exists and is Released (Package2 + Package2Version live on DevHub). It is NOT a hard prerequisite: if DevHub is unavailable the skill can still finalize, because the Connect endpoint validates eligibility server-side and returns a 400 with a specific reason (e.g. version mismatch) when the latest released version has not been converted + promoted. Skipping the pre-check trades a clear up-front message for a server-side reject; it does not make the workflow unsafe (the irreversibility is gated by the three affirmations, not by DevHub). (check: `DevHubOrgAuthenticated`)
46
+ - User must have the CreatePackaging user permission (which implies CustomizeApplication) plus dev-org ownership of the package. This is the exact edit-access gate the finalize Connect endpoint enforces server-side — the same edit-access check the package's Setup detail page applies. A caller lacking it gets a 403 from the endpoint before any state is inspected (note: sysadmins do NOT clear this gate — edit access is org-dev scoped, not sysadmin-scoped). (check: `UserPermissions.CreatePackaging`)
47
+ - Package conversion testing must be complete. Per the Salesforce documentation, "Before you complete your move to 2GP package development, it's critical that you thoroughly test package conversions and subscriber migrations first." An agent MUST explicitly confirm this with the user before proceeding to the finalize step. See "Test Converted Packages and Subscriber Migrations" (linked from the workflow doc) for the testing checklist. (check: `ConversionTestingComplete`)
48
+ - Source files for the package's latest converted version should be retrieved before finalize. Per the docs, the user runs `sf package version retrieve --package 04tXXX --output-dir my-folder --target-dev-hub <devhub>` to retrieve, then edits sfdx-project.json's versionName, versionNumber, and ancestorVersion. This is preparatory work for ongoing 2GP development AFTER finalize, but the doc places it in the workflow sequence — the agent should remind the user. (check: `PackageSourceRetrievedAndProjectFileUpdated`)
49
+
50
+ **Operational rules:**
51
+
52
+ - AT START — the finalize path needs ONE org: the 1GP DE (packaging) org, reachable with valid credentials. A DevHub org is OPTIONAL-but-recommended, used only to proactively pre-check eligibility. Auth is not coupled to the `sf` CLI: an `sf` alias is convenient, but any valid bearer token for the org works for a raw REST call. Ask the user for the packaging-org alias (and, if they want the eligibility pre-check, the DevHub alias) at the start if not already provided; `sf org list --json` confirms what's authed. If the packaging org is missing, instruct the user to make it reachable (e.g. `sf org login web --alias <name>`) and wait. If only DevHub is missing you may still finalize — skip the DevHub-side eligibility queries and rely on the endpoint's server-side validation (a not-yet-converted/not-promoted package returns a 400 with a specific reason), and tell the user the proactive pre-check was skipped.
53
+ MULTI-ORG DISPATCH (read once, important): this workflow spans two orgs — the 1GP DE (packaging) org and the DevHub org. Each step's `invocation` block carries a `target_org` field naming which org the call must hit (`{packaging_org_alias}` vs `{devhub_alias}`); route each call to the org its `target_org` names rather than assuming a single org for the whole workflow. Route to the DevHub org: discover-package-on-devhub, check-eligibility-2gp-converted-released, and check-already-done. Route to the packaging org: check-eligibility-1gp-released, finalize-move-to-2gp, and verify-finalize-on-packaging-org. If your execution channel can only reach one connected org at a time, run each off-target read-only step against the org named in its `target_org` before dispatching the finalize against the packaging org; a CLI-driven runner can map that routing onto its own tooling. A step sent to the wrong org returns empty or misleading results.
54
+ TWO ROOT INTENTS — pick by user phrasing.
55
+ INTENT A — "tell me how to move my package to 2GP" (planning /
56
+ education): walk the user through the full sequence —
57
+ discover-package-on-devhub → check-eligibility-1gp-released →
58
+ check-eligibility-2gp-converted-released → check-already-done →
59
+ remind-of-prerequisites (testing, source retrieval) → describe the
60
+ manual finalize step in Setup. Treat this as a planning
61
+ conversation, NOT a dispatch action.
62
+ - INTENT B — "do the move-to-2GP step now" (action request):
63
+ discover-package-on-devhub → check-eligibility-1gp-released →
64
+ check-eligibility-2gp-converted-released → check-already-done →
65
+ confirm-affirmations → finalize-move-to-2gp (direct Connect API
66
+ dispatch) → verify-finalize-on-packaging-org (wire-verify against
67
+ PackageConversion.EndDate) → verify-finalize-by-user-confirmation
68
+ (optional cross-check). The finalize step now dispatches the
69
+ packaging Connect API POST directly against the 1GP DE org — the
70
+ agent does NOT open a browser tab in the normal path. It MUST
71
+ still obtain the three explicit affirmations in confirm-affirmations
72
+ first (the endpoint requires all three flags true and rejects the
73
+ call otherwise), then POST, then wire-verify EndDate. The manual
74
+ browser fallback path is retained only as a fallback for orgs on a
75
+ pre-266 release (see finalize-move-to-2gp.invocation.fallback).
76
+ - HARD STOP CONTRACT: this workflow is irrevocable. Per the documentation's "After you click Proceed, you can no longer create new major or minor versions in the packaging org." An agent MUST NOT instruct the user to click Proceed in Setup until ALL THREE of the following have been explicitly confirmed: (a) conversion testing is done, (b) subscriber migration testing is done, (c) the user understands the irreversibility. Skipping any of these is a contract violation regardless of how the user phrased the original request.
77
+ EARLY EXIT: if check-already-done returns ≥1 row (a Package2Version exists with ConvertedFromVersionId = NULL), the move-to-2GP has ALREADY been completed — or the package was 2GP-native to start with. Report this to the user and stop. Do NOT proceed to affirmations or finalize.
78
+ ELIGIBILITY GATING: if check-eligibility-1gp-released returns no Released 1GP version, OR if check-eligibility-2gp-converted-released returns no matching Released 2GP-converted version at the same major.minor, the user is NOT eligible to Move to 2GP. Surface the specific missing piece and what to do — typically "you need to promote 2GP version X.Y to Released before you can move-to-2GP." If DevHub is not authenticated, skip the proactive 2GP eligibility query and rely on the endpoint's server-side validation instead — the finalize call returns a 400 with a specific reason (e.g. version mismatch) when the latest released version has not been converted + promoted; relay that message to the user.
79
+ RELEASE HISTORY (both milestones now shipped — describe-only, not an ongoing constraint): 264 shipped the read-only PackageConversion Tooling exposure, lighting up verify-finalize-on-packaging-org (EndDate-based wire-verify). 266 shipped the finalize Connect API — finalize-move-to-2gp now dispatches POST /services/data/v69.0/connect/packaging/package/{packageId}/finalize-move-to-2gp against the 1GP DE org (invocation.kind: rest, operationId finalizeMoveTo2gp, MCP-enabled). The endpoint requires the three affirmation flags (acknowledgedIrrevocable / acknowledgedTestingComplete / acknowledgedSourceRetrieved) all true in the request body, mirroring the Setup dialog's checkboxes — this is the load-bearing safety gate, so the confirm-affirmations step remains mandatory. For orgs still on a pre-266 release, the manual browser fallback applies.
80
+ Only the 1GP DE (packaging) org is required for the finalize dispatch + wire-verify. The DevHub org is optional — used only for the proactive eligibility pre-check; the endpoint validates eligibility server-side regardless.
81
+
82
+ ## Verification Checklist
83
+
84
+ After every write operation, confirm the effect by re-reading state:
85
+
86
+ - After `finalize-move-to-2gp`: call `verify-finalize-by-user-confirmation`
87
+ - After `verify-finalize-by-user-confirmation`: call `verify-finalize-on-packaging-org`
88
+
89
+ Read [Operations reference](references/api-operations.md) before executing this workflow. It contains the original operation definitions, dependencies, inputs, and verification instructions.
@@ -0,0 +1,164 @@
1
+ # Move to 2GP Operations Reference
2
+
3
+ Operations grouped by purpose. Use these as the building blocks for the workflows above.
4
+
5
+ ### Summary
6
+
7
+ | Operation | Purpose | Status | Call | Depends on |
8
+ |-----------|---------|--------|------|------------|
9
+ | `discover-package-on-devhub` | read | implemented | `queryPackage2ByConvertedFrom` | — |
10
+ | `check-eligibility-1gp-released` | validate | implemented | `queryHighestReleased1GPVersion` | `discover-package-on-devhub` |
11
+ | `check-eligibility-2gp-converted-released` | validate | implemented | `queryReleased2GPConvertedVersion` | `check-eligibility-1gp-released` |
12
+ | `check-already-done` | validate | implemented | `queryNativePackage2Version` | `check-eligibility-2gp-converted-released` |
13
+ | `confirm-affirmations` | validate | implemented | — | `check-already-done` |
14
+ | `finalize-move-to-2gp` | write | implemented | `finalizeMoveTo2gp` | `confirm-affirmations` |
15
+ | `verify-finalize-by-user-confirmation` | verify | implemented | — | `finalize-move-to-2gp` |
16
+ | `verify-finalize-on-packaging-org` | verify | implemented | `queryPackageConversion` | `verify-finalize-by-user-confirmation` |
17
+
18
+ ### Dependency graph
19
+
20
+ ```mermaid
21
+ graph TD
22
+ discover_package_on_devhub["discover-package-on-devhub (read)"]
23
+ check_eligibility_1gp_released["check-eligibility-1gp-released (validate)"]
24
+ check_eligibility_2gp_converted_released["check-eligibility-2gp-converted-released (validate)"]
25
+ check_already_done["check-already-done (validate)"]
26
+ confirm_affirmations["confirm-affirmations (validate)"]
27
+ finalize_move_to_2gp["finalize-move-to-2gp (write)"]
28
+ verify_finalize_by_user_confirmation["verify-finalize-by-user-confirmation (verify)"]
29
+ verify_finalize_on_packaging_org["verify-finalize-on-packaging-org (verify)"]
30
+ discover_package_on_devhub --> check_eligibility_1gp_released
31
+ check_eligibility_1gp_released --> check_eligibility_2gp_converted_released
32
+ check_eligibility_2gp_converted_released --> check_already_done
33
+ check_already_done --> confirm_affirmations
34
+ confirm_affirmations --> finalize_move_to_2gp
35
+ finalize_move_to_2gp --> verify_finalize_by_user_confirmation
36
+ verify_finalize_by_user_confirmation --> verify_finalize_on_packaging_org
37
+ ```
38
+
39
+ ### Read operations
40
+
41
+ #### `discover-package-on-devhub`
42
+
43
+ Look up the 2GP Package2 record on DevHub for the 1GP package the user wants to move. The user provides the 1GP package by name (the customer-facing label) or by SubscriberPackageId (the 033... key prefix). Returns the Package2 Id (0Ho... key prefix) and namespace prefix, plus the SubscriberPackageId for use in eligibility queries. This is the DevHub-side anchor for the DevHub-side eligibility checks; the 1GP-side eligibility check uses the SubscriberPackageId (which equals the MetadataPackage Id on the 1GP DE org) directly.
44
+
45
+ **Call:** `queryPackage2ByConvertedFrom` — status: `implemented`
46
+
47
+ **Inputs:**
48
+
49
+ - `devhub_alias` *(`String`)* — Source: user_input. The `sf` alias of the user's DevHub org. Captured at skill start (see agent_guidance "AT START").
50
+ - `subscriber_package_id` *(`String`)* — The 1GP package's SubscriberPackageId (033... key prefix). User provides this directly, or agent obtains it via a MetadataPackage name lookup on the 1GP DE org (see agent_guidance).
51
+
52
+ ### Write operations
53
+
54
+ #### `finalize-move-to-2gp`
55
+
56
+ Irrevocably finalize the Move-to-2GP transition by POSTing to the packaging Connect API endpoint `POST /services/data/v69.0/connect/packaging/package/{packageId}/finalize-move-to-2gp` against the 1GP DE (packaging) org. `{packageId}` is the 1GP MetadataPackage Id (033- prefix). The request body carries the three affirmation flags — acknowledgedIrrevocable, acknowledgedTestingComplete, acknowledgedSourceRetrieved — all required and all must be true (these are exactly what the user confirmed in confirm-affirmations). Server-side the endpoint enforces the CreatePackaging edit-access gate, re-validates the three affirmations, confirms the URL packageId matches the org's in-progress conversion, then finalizes it — after which PackageConversion.EndDate is set. Shipped in 266 (operationId finalizeMoveTo2gp, MCP-enabled). On success returns successfullyFinalized, finalizedAt, packageId, and conversionId. For orgs on a pre-266 release, fall back to the manual browser path (invocation.fallback) which delivers the user to viewAllPackage.apexp to click "Move to 2GP" → Proceed.
57
+
58
+ **Call:** `finalizeMoveTo2gp` — status: `implemented`
59
+
60
+ **Inputs:**
61
+
62
+ - `packaging_org_alias` *(`String`)* — Source - output of confirm-affirmations (transitively from check-eligibility-1gp-released.packaging_org_alias). The `sf` alias of the user's 1GP DE (packaging) org.
63
+ - **Source:** output of `check-eligibility-1gp-released`
64
+ - `subscriber_package_id` *(`String`)* — Source - output of confirm-affirmations (transitively from discover-package-on-devhub.subscriber_package_id). The 1GP MetadataPackage's SubscriberPackageId / 033- prefix.
65
+ - **Source:** output of `discover-package-on-devhub`
66
+ - `acknowledged_irrevocable` *(`Boolean`)* — Source - output of confirm-affirmations (acknowledged_irrevocable).
67
+ - `acknowledged_testing_complete` *(`Boolean`)* — Source - output of confirm-affirmations (acknowledged_testing_complete).
68
+ - `acknowledged_source_retrieved` *(`Boolean`)* — Source - output of confirm-affirmations (acknowledged_source_retrieved).
69
+
70
+ **Depends on:** `confirm-affirmations`
71
+
72
+ ### Verify operations
73
+
74
+ #### `verify-finalize-by-user-confirmation`
75
+
76
+ Human cross-check for the pre-266 manual fallback path ONLY: ask the user what the Setup page showed after they clicked Proceed. This step applies only when finalize-move-to-2gp took its manual browser fallback (org on a pre-266 release). In the normal 266 path the agent dispatches the finalize directly and the user never interacts with a browser, so this step is skipped — the endpoint's own response (successfullyFinalized / finalizedAt / conversionId) plus verify-finalize-on-packaging-org's EndDate wire-verify are the authoritative signals. Retained because the fallback still needs a verification surface when no direct-dispatch response exists.
77
+
78
+ **Status:** `implemented`
79
+
80
+ **Inputs:**
81
+
82
+ - `package_name` *(`String`)* — Source - output of finalize-move-to-2gp (transitively from discover-package-on-devhub.package_name).
83
+ - **Source:** output of `discover-package-on-devhub`
84
+
85
+ **Depends on:** `finalize-move-to-2gp`
86
+
87
+ #### `verify-finalize-on-packaging-org`
88
+
89
+ The canonical wire-verification: re-query the PackageConversion record on the 1GP DE org to confirm EndDate is populated (non-null). EndDate is set by the package-conversion finalization service as part of finalize and is the reliable post-finalize wire signal. Uses the read-only PackageConversion Tooling exposure shipped in 264 (1GP DE org auth is already a hard precondition for this skill, so no auth-state branching needed). This is the canonical wire-verify and supplements (rather than replaces) the optional user attestation in verify-finalize-by-user-confirmation. Note: the finalize step's own 266 response also returns finalizedAt + conversionId directly, so this step is a durable cross-check rather than the sole success signal.
90
+
91
+ **Call:** `queryPackageConversion` — status: `implemented`
92
+
93
+ **Inputs:**
94
+
95
+ - `packaging_org_alias` *(`String`)* — Source - output of verify-finalize-by-user-confirmation (transitively from check-eligibility-1gp-released.packaging_org_alias).
96
+ - **Source:** output of `check-eligibility-1gp-released`
97
+ - `subscriber_package_id` *(`String`)* — Source - output of verify-finalize-by-user-confirmation (transitively from discover-package-on-devhub.subscriber_package_id).
98
+ - **Source:** output of `discover-package-on-devhub`
99
+
100
+ **Depends on:** `verify-finalize-by-user-confirmation`
101
+
102
+ **Notes:** 264 shipped the read-only public Tooling exposure of PackageConversion (available when packaging is enabled for the org). The fields queried here — Id, EndDate, FinalizedVersionId (FK → SubscriberPackageVersion), FinalizedVersionNumber, and the WHERE key ConvertedFromPackageId (FK → SubscriberPackage) — are all exposed read-only. EndDate non-null means finalize completed. Move-to-2GP does NOT auto-create native Package2Version records on DevHub (native creation is a separate user-driven step), so there is no Package2Version-based wire-verify; EndDate is the reliable signal.
103
+
104
+ ### Other operations
105
+
106
+ #### `check-eligibility-1gp-released`
107
+
108
+ Find the highest Released 1GP major.minor version of the package by querying MetadataPackageVersion on the 1GP DE org. MetadataPackageVersion is the 1GP DE-side view of `all_package_version` joined with `dev_package_version`, with a `ReleaseState` STATICENUM field whose Released picklist value is `"Released"`.
109
+
110
+ **Call:** `queryHighestReleased1GPVersion` — status: `implemented`
111
+
112
+ **Inputs:**
113
+
114
+ - `packaging_org_alias` *(`String`)* — Source: user_input. The `sf` alias of the user's 1GP DE (packaging) org. Captured at skill start (see agent_guidance "AT START").
115
+ - `subscriber_package_id` *(`String`)* — Source - output of discover-package-on-devhub. Note: the SubscriberPackageId (033... key prefix) on DevHub is the same Id as MetadataPackage on the 1GP DE org — both wrap the same all_package row.
116
+
117
+ **Depends on:** `discover-package-on-devhub`
118
+
119
+ #### `check-eligibility-2gp-converted-released`
120
+
121
+ Confirm a 2GP-converted Package2Version exists at the same major.minor as the highest Released 1GP version, AND that the 2GP version is Released. This is the second half of the eligibility gate — Move-to-2GP requires the highest 1GP major.minor to have a corresponding RELEASED 2GP-converted equivalent. Queries Package2Version on DevHub.
122
+
123
+ **Call:** `queryReleased2GPConvertedVersion` — status: `implemented`
124
+
125
+ **Inputs:**
126
+
127
+ - `devhub_alias` *(`String`)* — Source - output of check-eligibility-1gp-released (transitively from discover-package-on-devhub.devhub_alias).
128
+ - **Source:** output of `discover-package-on-devhub`
129
+ - `package2_id` *(`String`)* — Source - output of check-eligibility-1gp-released (transitively from discover-package-on-devhub.package2_id).
130
+ - **Source:** output of `discover-package-on-devhub`
131
+ - `major` *(`Integer`)* — Source - output of check-eligibility-1gp-released (highest_1gp_major).
132
+ - `minor` *(`Integer`)* — Source - output of check-eligibility-1gp-released (highest_1gp_minor).
133
+
134
+ **Depends on:** `check-eligibility-1gp-released`
135
+
136
+ #### `check-already-done`
137
+
138
+ Detect the early-exit case — if a native (non-converted) Package2Version exists for this Package2, Move-to-2GP has ALREADY happened OR the package was 2GP-native to start with. Native 2GP versions are characterized by ConvertedFromVersionId = NULL. If any such Package2Version exists, the skill exits immediately.
139
+
140
+ **Call:** `queryNativePackage2Version` — status: `implemented`
141
+
142
+ **Inputs:**
143
+
144
+ - `devhub_alias` *(`String`)* — Source - output of check-eligibility-2gp-converted-released (transitively from discover-package-on-devhub.devhub_alias).
145
+ - **Source:** output of `discover-package-on-devhub`
146
+ - `package2_id` *(`String`)* — Source - output of check-eligibility-2gp-converted-released (transitively from discover-package-on-devhub.package2_id).
147
+ - **Source:** output of `discover-package-on-devhub`
148
+
149
+ **Depends on:** `check-eligibility-2gp-converted-released`
150
+
151
+ #### `confirm-affirmations`
152
+
153
+ Present the irrevocability + testing affirmations to the user, mirroring the "Move to Second-Generation Managed Packaging" dialog shown in Setup UI. The user must explicitly confirm each affirmation before the agent proceeds to the (manual) finalize step. This step has no API surface — it's a structured agent-to-user interaction encoded in the SOR for contract consistency between the eventual 266 Connect API (which is expected to require these as request-body fields) and the pre-266 manual flow.
154
+
155
+ **Status:** `implemented`
156
+
157
+ **Inputs:**
158
+
159
+ - `package_name` *(`String`)* — Source - output of check-already-done (transitively from discover-package-on-devhub.package_name).
160
+ - **Source:** output of `discover-package-on-devhub`
161
+ - `package2_id` *(`String`)* — Source - output of check-already-done (transitively from discover-package-on-devhub.package2_id).
162
+ - **Source:** output of `discover-package-on-devhub`
163
+
164
+ **Depends on:** `check-already-done`
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: dx-scratch-def-configure
3
+ description: "Drafts a schema-valid Salesforce DX scratch-def from natural language. Preview first (confirmation card, do not write). A later edit — including a write that also changes the draft — is another preview. Write only on consent that this draft is unchanged: invoke this skill and apply via its helper — never hand-write JSON with Write. Writes config/<purpose>-scratch-def.json (default purpose project) under an existing SF DX project that already has config/ (never creates config/). Grounds features on the PUBLIC config-values catalog: put product names (like Revenue Cloud) in features as-is. Use to author/validate a scratch-def or layer features onto a shape or snapshot. Also use for trial, shape-only, snapshot-only, underspecified, missing config/ (ask for the SF DX project path), or batch multi-def asks: invoke this skill, STOP, write report.md on disk (chat is not a substitute; do not skip the skill). Does not create orgs or enable Dev Hub. Not for dx-org-manage, dx-org-devhub-configure, or SKU work."
4
+ allowed-tools: Read, Write, Bash(python3), Bash(python)
5
+ metadata:
6
+ version: "1.0"
7
+ domains: ["Developer Experience"]
8
+ relatedSkills:
9
+ - "dx-org-devhub-configure"
10
+ - "dx-org-manage"
11
+ - "dx-org-shape-manage"
12
+ - "dx-org-snapshot-manage"
13
+ - "platform-trial-org-create"
14
+ cliTools:
15
+ - tool: ["python3", "python"]
16
+ semver: ">=3.8.0"
17
+ ---
18
+
19
+ # Configure Scratch Org Definition File
20
+
21
+ This skill writes `config/<purpose>-scratch-def.json` (default
22
+ `config/project-scratch-def.json`) from a product ask. It does **not** create
23
+ the org. Never `mkdir config`.
24
+
25
+ Every turn writes `report.md` on disk. Chat is not a substitute. Then exactly
26
+ one of these happens:
27
+
28
+ | Mode | When | What the user gets |
29
+ |------|------|--------------------|
30
+ | **Stop** | Trial, shape-only, shape/snapshot + features with no id, missing project, unclear ask, batch, other-user path | The next step, named. No scratch-def file. |
31
+ | **Preview** | First generate (including just-write / skip-preview) or a revision, and the project already has `config/` | A draft + Write file?. Nothing is written yet. |
32
+ | **Write** | They accept this draft **unchanged** (this preview, as drafted). This turn may restate it; no prior chat required. | The file. Name dx-org-manage. |
33
+
34
+ ## CRITICAL first gate (before any helper)
35
+
36
+ First matching row wins. Copy that recipe into `report.md`.
37
+
38
+ Never Skill() another skill. Never run `sf`. Name the next skill in `report.md` only.
39
+
40
+ STOP: write `report.md` on disk. Chat is not a substitute. Skip the helper
41
+ and skip scratch-def JSON.
42
+
43
+ Consent is accepting this draft, **unchanged** — not a closed list of yes-words.
44
+ Accepting this draft (this preview, as drafted) and asking to write is consent:
45
+ apply; reconstruct if they restate the same draft; do not ask Write file?.
46
+ A first generate is Preview even if they say write or skip preview.
47
+ A different edition, product, or setting is a change: preview.
48
+
49
+ | If the ask is… | Then |
50
+ |----------------|------|
51
+ | Shape or snapshot **lifecycle alone** (no features to layer), including "use my org shape only" | STOP. Name dx-org-shape-manage or dx-org-snapshot-manage. |
52
+ | Trial / trialforce / "trial org definition" | STOP. Name platform-trial-org-create. Do **not** skip this skill. |
53
+ | Underspecified ("I need a scratch def") — no edition and no products/clouds/features | STOP. Ask the two questions below. If `config/` is also missing, include the Missing-project question. Do not invent an edition. |
54
+ | Another user's laptop / no readable workspace path | STOP. Cannot read another user's machine. Ask for a readable workspace path. |
55
+ | Batch generation (multiple def files in one turn), e.g. "Generate 5 def files for different personas" | STOP. Batch generation is not supported yet — offer to make the first one. |
56
+ | WRITE-eligible (imperative generate with edition and/or products/features, or shape/snapshot **+ features**) but cwd has **no** `config/` | STOP. Ask the Missing-project question (folder that **already** contains `config/`). Do **not** create `config/`. |
57
+ | Shape/snapshot **+ features**, root resolved, user omitted `sourceOrg` or snapshot id/name | STOP. Write `report.md` on disk. Ask for the id. Name dx-org-shape-manage / dx-org-snapshot-manage to list. Resume this skill with the id. |
58
+ | User revises the draft — this turn names a **different** edition, products, settings, or other edits, including a write request that also changes the draft, and root resolved | This turn's wording is the full draft. Preview it. Do not require a prior file or earlier chat. **Do not** apply yet. |
59
+ | User consents that this preview is the draft they want written, **unchanged** (this preview, as drafted), and root resolved | Write it. Reconstruct if this turn restates the same draft. No prior chat required. See **Write**. |
60
+ | Shape/snapshot **+ features**, root resolved, user supplied the id, and this turn is not consent to write | Preview it. **Do not** apply yet. |
61
+ | Imperative generate that names edition and/or products/features (one def), including a first-turn write or skip-preview ask, root resolved, and this turn is not consent to write | Preview it. **Do not** apply yet. |
62
+
63
+ Underspecified questions: (1) what are you building/demoing? (2) which products/clouds?
64
+
65
+ Missing-project question: What is the path to your Salesforce DX project (the directory that already contains a config folder)?
66
+
67
+ ## Preview
68
+
69
+ Show the confirmation card (see `examples/confirm-card.md`, or
70
+ `artifacts/examples/confirm-card.md` when packaged). Put **schema-valid JSON**
71
+ in chat alongside `report.md` (never inside it): the helper `document`. Ask
72
+ Write file? in `report.md`. **Do not** apply yet. Do not name dx-org-manage
73
+ until they consent to write.
74
+
75
+ ## Write
76
+
77
+ One `apply` only — no preview, no second card, no Write file?. Reconstruct
78
+ if this turn restates the same draft (no in-context copy). `--out config/<purpose>-scratch-def.json`
79
+ (default `config/project-scratch-def.json`). Report the path + a one-line
80
+ summary + the **final written JSON in chat**. Name dx-org-manage
81
+ (dx-org-devhub-configure if Dev Hub is off).
82
+
83
+ ## Outcome report (always)
84
+
85
+ **Read** `examples/report-recipes.md` (or `artifacts/examples/report-recipes.md`
86
+ when packaged) and copy the matching recipe. First line: `# Scratch Def Report`.
87
+ Plain prose — never the backtick character. Spell next-skill names as plain
88
+ words (dx-org-shape-manage, platform-trial-org-create).
89
+
90
+ Omit cache date, shipped-snapshot, jsonschema, and dropped-token notes from
91
+ `report.md` unless the helper warned this turn.
92
+
93
+ ## Steps
94
+
95
+ 1. Run the CRITICAL first gate. If it is STOP, write `report.md` and stop here.
96
+
97
+ 2. On WRITE-eligible asks, **resolve the SF DX project root before any helper**:
98
+ cwd with `config/` is the root; otherwise the Missing-config STOP row.
99
+
100
+ 3. Resolve the helper by absolute path:
101
+
102
+ ```bash
103
+ HELPER="<skill_dir>/scripts/lib_scratch_def.py"
104
+ [ -f "$HELPER" ] || HELPER="<skill_dir>/artifacts/scripts/lib_scratch_def.py"
105
+ ```
106
+
107
+ 4. **One helper call per turn** from the SF DX project root. Keep the draft in
108
+ **chat/tool context**. Pass the draft on stdin with a quoted heredoc
109
+ (`<<'EOF'`). Invoke `python3` when that binary exists; otherwise `python`.
110
+ - Preview (generate or a revision of the draft):
111
+ ```bash
112
+ python3 "$HELPER" preview <<'EOF'
113
+ {"edition":"Developer","features":["API"]}
114
+ EOF
115
+ ```
116
+ - After consent that this draft is what they want, unchanged:
117
+ ```bash
118
+ python3 "$HELPER" apply --out config/<purpose>-scratch-def.json <<'EOF'
119
+ …same draft JSON…
120
+ EOF
121
+ ```
122
+ (default `config/project-scratch-def.json`). `--out` writes the scratch-def.
123
+ If the helper warns `jsonschema not installed`, ask the user to install
124
+ (`python3 -m pip install jsonschema` or `python -m pip install jsonschema`).
125
+ On success, retry this same helper call once. If they decline or install fails,
126
+ keep this result — do **not** block preview/apply.
127
+ Do **not** Read `references/features.json` or `settings-map.json` into chat.
128
+ Do not Grep them to pick extra tokens.
129
+
130
+ 5. Put the user's product, cloud, and feature words in the `features` array
131
+ as-is (for example Revenue Cloud, not a guessed token list). Use lower
132
+ camelCase settings keys. The helper maps each string to at most one PUBLIC
133
+ token and enriches required settings. Do not add catalog tokens the user
134
+ did not name.
135
+
136
+ 6. Write `report.md` on disk. Put chat JSON and the card per Preview / Write.
137
+
138
+ Unknown token: drop it and warn in report.md.
139
+
140
+ ## Before you finish
141
+
142
+ - [ ] `report.md` exists on disk and matches a recipe
143
+ - [ ] Preview / revision (including write + change): this turn's wording is the full draft; card + document JSON in chat; asked Write file?; **Do not** apply yet
144
+ - [ ] Consent unchanged (this preview, as drafted; no prior chat required): `apply`; file + final JSON in chat; no Write file?; name dx-org-manage
145
+ - [ ] WRITE turns: root resolved; one helper call; features array is the user's words
146
+ - [ ] report.md mentions cache date, jsonschema, or dropped tokens only when the helper warned this turn
147
+
148
+ ## Notes
149
+
150
+ Catalog: each helper invocation loads maps into process memory from:
151
+
152
+ 1. Today's `cache/public-config-values-YYYY-MM-DD.json` if usable.
153
+ 2. Else GET live PUBLIC config-values markdown; on success write today's cache file.
154
+ 3. Else newest usable prior dated file in `cache/`. report.md: that date
155
+ (only when this fallback fired).
156
+ 4. Else shipped snapshot JSON `references/features.json` + `settings-map.json`
157
+ (`artifacts/references/` when packaged). Backup. report.md: shipped snapshot
158
+ (only when this fallback fired).
159
+
160
+ Every helper call (`preview` and `apply`) may write today's cache file under
161
+ `cache/` before the user confirms the scratch-def. Add `cache/` to `.gitignore`.
162
+ Treat cache JSON as generated. Delete is safe: the next call refetches if
163
+ today's file is missing. Feature tokens come from this catalog.