@salesforce/afv-skills 1.49.0 → 1.51.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 (58) hide show
  1. package/package.json +1 -1
  2. package/skills/experience-ui-bundle-deploy/SKILL.md +43 -2
  3. package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +16 -3
  4. package/skills/experience-ui-bundle-deploy/references/logout-url.md +97 -0
  5. package/skills/experience-ui-bundle-deploy/scripts/set-logout-url.mjs +304 -0
  6. package/skills/experience-ui-bundle-localize/SKILL.md +107 -90
  7. package/skills/experience-ui-bundle-localize/references/angular/check-i18n-wired.sh +159 -0
  8. package/skills/experience-ui-bundle-localize/references/angular/i18n-setup.md +250 -0
  9. package/skills/experience-ui-bundle-localize/references/angular/interpolation.md +156 -0
  10. package/skills/experience-ui-bundle-localize/references/angular/localize.md +111 -0
  11. package/skills/experience-ui-bundle-localize/references/{gotchas.md → common/gotchas.md} +27 -43
  12. package/skills/experience-ui-bundle-localize/references/{label-xml.md → common/label-xml.md} +27 -17
  13. package/skills/experience-ui-bundle-localize/references/common/platform-sdk-i18n.md +169 -0
  14. package/skills/experience-ui-bundle-localize/references/{verifying.md → common/verifying.md} +26 -16
  15. package/skills/experience-ui-bundle-localize/{scripts → references/react}/check-i18n-wired.sh +8 -3
  16. package/skills/experience-ui-bundle-localize/references/{i18n-setup.md → react/i18n-setup.md} +48 -10
  17. package/skills/experience-ui-bundle-localize/references/{interpolation.md → react/interpolation.md} +4 -4
  18. package/skills/experience-ui-bundle-localize/references/react/localize.md +76 -0
  19. package/skills/experience-ui-bundle-localize/scripts/check-manifest-registered.sh +92 -24
  20. package/skills/experience-ui-bundle-localize/scripts/detect-framework.sh +73 -0
  21. package/skills/experience-ui-bundle-site-generate/SKILL.md +1 -1
  22. package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +180 -0
  23. package/skills/field-service-data-capture-form-deployer-configure/examples/inventory-transfer-spec.json +135 -0
  24. package/skills/field-service-data-capture-form-deployer-configure/examples/sample-spec.json +140 -0
  25. package/skills/field-service-data-capture-form-deployer-configure/examples/sectioned-spec.json +64 -0
  26. package/skills/field-service-data-capture-form-deployer-configure/references/field-types.md +297 -0
  27. package/skills/field-service-data-capture-form-deployer-configure/references/flow-metadata-json.md +243 -0
  28. package/skills/field-service-data-capture-form-deployer-configure/references/post-screen-automation.md +127 -0
  29. package/skills/field-service-data-capture-form-designer-configure/SKILL.md +110 -0
  30. package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-image.md +244 -0
  31. package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-prompt.md +222 -0
  32. package/skills/field-service-data-capture-form-editor-configure/SKILL.md +134 -0
  33. package/skills/field-service-data-capture-reference-configure/SKILL.md +762 -0
  34. package/skills/field-service-data-capture-reference-configure/examples/DataCapture_Showcase.flow-meta.xml +2022 -0
  35. package/skills/field-service-data-capture-reference-configure/examples/Data_Capture_All_Components.flow-meta.xml +2170 -0
  36. package/skills/field-service-data-capture-reference-configure/examples/Repeater_with_prepopulation.flow-meta.xml +231 -0
  37. package/skills/field-service-foundation-setup-designer-get/SKILL.md +135 -0
  38. package/skills/field-service-mobile-branding-configure/SKILL.md +133 -0
  39. package/skills/field-service-mobile-branding-configure/examples/dark-blue-scheme.json +16 -0
  40. package/skills/field-service-mobile-branding-configure/examples/salesforce-default-scheme.json +16 -0
  41. package/skills/field-service-mobile-branding-configure/references/color-fields.md +66 -0
  42. package/skills/field-service-mobile-branding-configure/references/contrast-validation.md +55 -0
  43. package/skills/field-service-mobile-branding-configure/references/derivation-methodology.md +83 -0
  44. package/skills/field-service-objective-designer-configure/SKILL.md +342 -0
  45. package/skills/field-service-prework-brief-deployer-configure/SKILL.md +83 -0
  46. package/skills/field-service-scheduling-policy-designer-query/SKILL.md +121 -0
  47. package/skills/field-service-setup-orchestrator-get/SKILL.md +48 -0
  48. package/skills/field-service-sobject-create-configure/SKILL.md +56 -0
  49. package/skills/field-service-voice-to-form-configure/SKILL.md +650 -0
  50. package/skills/field-service-work-rule-designer-configure/SKILL.md +303 -0
  51. package/skills/service-digital-engagement-channel-configure/SKILL.md +20 -37
  52. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +3 -2
  53. package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -4
  54. package/skills/service-helpagent-coordinate/SKILL.md +37 -29
  55. package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +33 -28
  56. package/skills/service-helpagent-coordinate/references/agent-script.md +4 -1
  57. package/skills/service-helpagent-coordinate/references/channel-voice.md +1 -1
  58. package/skills/service-helpagent-coordinate/references/channel-web-chat.md +10 -12
@@ -0,0 +1,243 @@
1
+ # Flow Metadata JSON — Data Capture Flow
2
+
3
+ A Data Capture Flow is a Salesforce Flow with `processType=DataCaptureFlow`. It is created and updated through the **Tooling API `Flow` sObject**, whose `Metadata` field is a JSON object — the same shape you get back from `GET /services/data/vXX.0/tooling/sobjects/Flow/{id}`. There is **no `.flow-meta.xml`, no zip, and no SFDX project** — the agent assembles this JSON inline and POSTs it.
4
+
5
+ The shape below is the JSON transliteration of the Metadata blob retrieved from real flows in a live Field Service org (`Data_Capture_Asset_Inspection`, `Inventory_Transfer`) and verified against that org's `Flow` describe.
6
+
7
+ ## The deploy call
8
+
9
+ ```http
10
+ POST /services/data/vXX.0/tooling/sobjects/Flow
11
+ {
12
+ "FullName": "<FlowApiName>",
13
+ "Metadata": { ...the object below... }
14
+ }
15
+ ```
16
+
17
+ - `FullName` is the Flow API name (matches `^[A-Z][A-Za-z0-9_]*$`). `FullName` is set-on-create only.
18
+ - A 201 with `success: true` returns the new Flow version id.
19
+ - To **activate on create**, set `Metadata.status: "Active"`. Default `"Draft"` so the user reviews in Flow Builder first — activation is via `Flow.Metadata.status`, not a separate `FlowDefinition` write (`FlowDefinition.ActiveVersionId` is not directly writable).
20
+ - To **update** an existing version, `PATCH /services/data/vXX.0/tooling/sobjects/Flow/{id}` with `{"Metadata": {...full metadata...}}` (the editor skill's redeploy path).
21
+
22
+ ## JSON ↔ XML mapping rule
23
+
24
+ The Metadata JSON is a mechanical transliteration of the Flow XML:
25
+
26
+ - Each XML element becomes a JSON key. `<label>X</label>` → `"label": "X"`.
27
+ - **Repeated** elements become a JSON **array**: multiple `<screens>` → `"screens": [ {...}, {...} ]`; multiple `<choiceReferences>` → `"choiceReferences": ["A","B"]`.
28
+ - Typed value wrappers keep their wrapper key: `<value><stringValue>X</stringValue></value>` → `"value": {"stringValue": "X"}`; `<booleanValue>true</booleanValue>` → `{"booleanValue": true}`; `<numberValue>1.0</numberValue>` → `{"numberValue": 1.0}`; `<elementReference>Foo</elementReference>` → `{"elementReference": "Foo"}`.
29
+ - Booleans and numbers are real JSON scalars, not strings.
30
+
31
+ ## Minimum-deployable shape
32
+
33
+ ```json
34
+ {
35
+ "processType": "DataCaptureFlow",
36
+ "environments": ["Offline"],
37
+ "areMetricsLoggedToDataCloud": false,
38
+ "label": "HVAC Compressor Inspection",
39
+ "interviewLabel": "HVAC Compressor Inspection {!$Flow.CurrentDateTime}",
40
+ "description": "Generated from spec: HVAC Compressor Inspection",
41
+ "status": "Draft",
42
+
43
+ "processMetadataValues": [
44
+ { "name": "BuilderType", "value": { "stringValue": "LightningFlowBuilder" } },
45
+ { "name": "CanvasMode", "value": { "stringValue": "AUTO_LAYOUT_CANVAS" } }
46
+ ],
47
+
48
+ "choices": [
49
+ { "name": "Good", "choiceText": "Good", "dataType": "String", "value": { "stringValue": "Good" } }
50
+ ],
51
+
52
+ "start": { "locationX": 0, "locationY": 0, "connector": { "targetReference": "Screen_HeaderInformation" } },
53
+
54
+ "screens": [
55
+ {
56
+ "name": "Screen_HeaderInformation",
57
+ "label": "Header Information",
58
+ "locationX": 0, "locationY": 0,
59
+ "allowBack": true, "allowFinish": true, "allowPause": true,
60
+ "showFooter": true, "showHeader": true,
61
+ "connector": { "targetReference": "Screen_OperatingParameters" },
62
+ "fields": [
63
+
64
+ {
65
+ "name": "jobName",
66
+ "extensionName": "runtime_service_fieldservice:dcTextInput",
67
+ "fieldType": "ComponentInstance",
68
+ "inputParameters": [
69
+ { "name": "label", "value": { "stringValue": "Job Name" } }
70
+ ],
71
+ "inputsOnNextNavToAssocScrn": "UseStoredValues",
72
+ "isRequired": true,
73
+ "storeOutputAutomatically": true,
74
+ "styleProperties": {
75
+ "verticalAlignment": { "stringValue": "top" },
76
+ "width": { "stringValue": "12" }
77
+ }
78
+ },
79
+
80
+ {
81
+ "name": "Quantity",
82
+ "extensionName": "runtime_service_fieldservice:dcCounter",
83
+ "fieldType": "ComponentInstance",
84
+ "inputParameters": [
85
+ { "name": "label", "value": { "stringValue": "Quantity" } },
86
+ { "name": "min", "value": { "numberValue": 1.0 } },
87
+ { "name": "value", "value": { "numberValue": 1.0 } }
88
+ ]
89
+ },
90
+
91
+ {
92
+ "name": "To",
93
+ "choiceReferences": ["Truck", "Work_Order"],
94
+ "extensionName": "runtime_service_fieldservice:dcRbGroup",
95
+ "fieldText": "To",
96
+ "fieldType": "ComponentChoice"
97
+ },
98
+
99
+ {
100
+ "name": "issuesIdentified",
101
+ "choiceReferences": ["Corrosion", "Wear", "Leakage"],
102
+ "extensionName": "runtime_service_fieldservice:dcCbGroup",
103
+ "fieldText": "Issues Identified",
104
+ "fieldType": "ComponentMultiChoice"
105
+ },
106
+
107
+ {
108
+ "name": "Work_Order_Number",
109
+ "extensionName": "runtime_service_fieldservice:dcTextInput",
110
+ "fieldType": "ComponentInstance",
111
+ "inputParameters": [
112
+ { "name": "label", "value": { "stringValue": "Work Order Number" } }
113
+ ],
114
+ "isRequired": true,
115
+ "visibilityRule": {
116
+ "conditionLogic": "and",
117
+ "conditions": [
118
+ { "leftValueReference": "Work_Order", "operator": "EqualTo", "rightValue": { "booleanValue": true } }
119
+ ]
120
+ }
121
+ },
122
+
123
+ {
124
+ "name": "Part",
125
+ "fieldType": "Repeater",
126
+ "fields": [
127
+ { "name": "Quantity", "extensionName": "runtime_service_fieldservice:dcCounter", "fieldType": "ComponentInstance" },
128
+ { "name": "Part_Number", "extensionName": "runtime_service_fieldservice:dcTextInput", "fieldType": "ComponentInstance" }
129
+ ],
130
+ "isRequired": false,
131
+ "styleProperties": { "verticalAlignment": { "stringValue": "top" }, "width": { "stringValue": "12" } }
132
+ },
133
+
134
+ {
135
+ "name": "safetyInstructions",
136
+ "fieldText": "<p>All personnel must wear PPE.</p>",
137
+ "fieldType": "DisplayText"
138
+ }
139
+ ]
140
+ }
141
+ ],
142
+
143
+ "decisions": [
144
+ {
145
+ "name": "Transfer_Location_Decision",
146
+ "label": "Transfer Location Decision",
147
+ "locationX": 0, "locationY": 0,
148
+ "defaultConnectorLabel": "Error",
149
+ "rules": [
150
+ {
151
+ "name": "Truck_Decision",
152
+ "conditionLogic": "and",
153
+ "conditions": [
154
+ { "leftValueReference": "To.selectedChoiceValues", "operator": "EqualTo", "rightValue": { "elementReference": "Truck" } }
155
+ ],
156
+ "connector": { "targetReference": "Get_Truck" },
157
+ "label": "Truck"
158
+ }
159
+ ]
160
+ }
161
+ ],
162
+
163
+ "recordLookups": [
164
+ {
165
+ "name": "Get_Truck",
166
+ "label": "Get Truck",
167
+ "locationX": 0, "locationY": 0,
168
+ "assignNullValuesIfNoRecordsFound": false,
169
+ "connector": { "targetReference": "Part_Transfers" },
170
+ "filterLogic": "and",
171
+ "filters": [
172
+ { "field": "Service_Resource__c", "operator": "EqualTo", "value": { "elementReference": "$User.Id" } }
173
+ ],
174
+ "object": "Location",
175
+ "outputAssignments": [
176
+ { "assignToReference": "Transfer_Destination", "field": "Id" }
177
+ ]
178
+ }
179
+ ],
180
+
181
+ "loops": [
182
+ {
183
+ "name": "Part_Transfers",
184
+ "label": "Part Transfers",
185
+ "locationX": 0, "locationY": 0,
186
+ "collectionReference": "Part.AddedItems",
187
+ "iterationOrder": "Asc",
188
+ "nextValueConnector": { "targetReference": "Transfer_Part" }
189
+ }
190
+ ],
191
+
192
+ "recordCreates": [
193
+ {
194
+ "name": "Transfer_Part",
195
+ "label": "Transfer Part",
196
+ "locationX": 0, "locationY": 0,
197
+ "connector": { "targetReference": "Part_Transfers" },
198
+ "inputAssignments": [
199
+ { "field": "Product2Id", "value": { "elementReference": "Part_Transfers.Part_Number.value" } }
200
+ ],
201
+ "object": "ProductTransfer",
202
+ "storeOutputAutomatically": true
203
+ }
204
+ ],
205
+
206
+ "variables": [
207
+ { "name": "parentObjectType", "dataType": "String", "isCollection": false, "isInput": true, "isOutput": false },
208
+ { "name": "parentRecordId", "dataType": "String", "isCollection": false, "isInput": true, "isOutput": false },
209
+ { "name": "recordId", "dataType": "String", "isCollection": false, "isInput": true, "isOutput": false },
210
+ { "name": "Transfer_Destination","dataType": "String", "isCollection": false, "isInput": false, "isOutput": false }
211
+ ]
212
+ }
213
+ ```
214
+
215
+ ## Field-rendering strategies
216
+
217
+ | Strategy | Triggered by | Key JSON differences |
218
+ |----------|--------------|----------------------|
219
+ | `ComponentInstance` | most types: TextInput, Email, Phone, Numeric, Counter, Date, DateTime, Checkbox, Toggle, LongText | `"fieldType": "ComponentInstance"`, label via `inputParameters` |
220
+ | `ComponentChoice` | Picklist, Radio (`dcRbGroup`) | `"fieldType": "ComponentChoice"`, label via `fieldText`, options via `choiceReferences` array |
221
+ | `ComponentMultiChoice` | CheckboxGroup | `"fieldType": "ComponentMultiChoice"`, label via `fieldText`, options via `choiceReferences` array |
222
+ | native `DisplayText` | DisplayText | `"fieldType": "DisplayText"`, body via `fieldText` (HTML), no `extensionName` |
223
+ | native `Repeater` | Repeater | `"fieldType": "Repeater"`, child fields via nested `fields` array, no `extensionName` |
224
+
225
+ ## Requiredness — `isRequired` only, never a `required` inputParameter
226
+
227
+ Mark a mandatory field with the field-level `"isRequired": true` key **only**. Do **not** add `{ "name": "required", ... }` to `inputParameters` — `dcName`, `dcSignature`, and other Field Service components reject it, and the deploy fails with `We can't find this input attribute: 'required'`. This is the single most common deploy error; the examples above intentionally carry `isRequired` with no `required` inputParameter.
228
+
229
+ ## Connector pattern
230
+
231
+ - `start.connector` points to screen #1.
232
+ - Each screen — *except* the last — has a `connector` to the next screen.
233
+ - The **last screen** connects to `postScreen` (decision/lookup/loop/create) if present, otherwise omits `connector`.
234
+ - All screens set `"allowFinish": true`.
235
+
236
+ ## Things deliberately not generated
237
+
238
+ - No formulas, assignments, or text templates.
239
+ - No nested loops or decisions inside loops.
240
+ - No subflows.
241
+ - No `dcLookup` without an `objectApiName` (specs missing `lookupObject` fall back to a labeled TextInput placeholder).
242
+ - No `dcFileView` without a `fileName` (specs missing `fileName` fall back to a labeled TextInput placeholder).
243
+ - No visual polish HTML (banners, progress bars, callouts).
@@ -0,0 +1,127 @@
1
+ # Post-screen automation: decision → lookup → loop → createRecord
2
+
3
+ The Inventory_Transfer flow in the demo org shows the canonical "do something with the captured data" chain. After the last screen, the flow:
4
+
5
+ 1. **Decides** which branch to take based on a Radio answer (Truck vs Work Order).
6
+ 2. **Looks up** a record per branch (the truck Location for the user, or the WorkOrder).
7
+ 3. **Stores** the resulting Id into a private variable (`Transfer_Destination`).
8
+ 4. **Loops** over the Repeater's `AddedItems` collection.
9
+ 5. **Creates** one Salesforce record per row, mapping the row's child-field values onto the target object.
10
+
11
+ This file documents the spec shape that drives that XML.
12
+
13
+ ## Spec extension
14
+
15
+ Add a top-level `postScreen` block:
16
+
17
+ ```json
18
+ {
19
+ "formTitle": "Inventory Transfer",
20
+ "formType": "Inventory",
21
+ "screens": { ... },
22
+ "postScreen": {
23
+ "variables": [
24
+ { "name": "Transfer_Destination", "type": "String" }
25
+ ],
26
+ "decision": {
27
+ "name": "Transfer_Location_Decision",
28
+ "label": "Transfer Location Decision",
29
+ "defaultLabel": "Error",
30
+ "branches": [
31
+ {
32
+ "name": "Truck_Decision",
33
+ "label": "Truck",
34
+ "when": { "field": "To", "operator": "EqualTo", "value": "Truck" },
35
+ "then": "Get_Truck"
36
+ },
37
+ {
38
+ "name": "Work_Order_Decision",
39
+ "label": "Work Order",
40
+ "when": { "field": "To", "operator": "EqualTo", "value": "Work Order" },
41
+ "then": "Get_WO"
42
+ }
43
+ ]
44
+ },
45
+ "recordLookups": [
46
+ {
47
+ "name": "Get_Truck",
48
+ "label": "Get Truck",
49
+ "object": "Location",
50
+ "filters": [
51
+ { "field": "Service_Resource__c", "operator": "EqualTo", "valueRef": "$User.Id" }
52
+ ],
53
+ "outputAssignments": [
54
+ { "assignTo": "Transfer_Destination", "field": "Id" }
55
+ ],
56
+ "next": "Part_Transfers"
57
+ },
58
+ {
59
+ "name": "Get_WO",
60
+ "label": "Get WO",
61
+ "object": "WorkOrder",
62
+ "filters": [
63
+ { "field": "Id", "operator": "EqualTo", "valueRef": "Work_Order_Number.value" }
64
+ ],
65
+ "outputAssignments": [
66
+ { "assignTo": "Transfer_Destination", "field": "LocationId" }
67
+ ],
68
+ "next": "Part_Transfers"
69
+ }
70
+ ],
71
+ "loop": {
72
+ "name": "Part_Transfers",
73
+ "label": "Part Transfers",
74
+ "collection": "Part.AddedItems",
75
+ "next": "Transfer_Part"
76
+ },
77
+ "recordCreates": [
78
+ {
79
+ "name": "Transfer_Part",
80
+ "label": "Transfer Part",
81
+ "object": "ProductTransfer",
82
+ "next": "Part_Transfers",
83
+ "inputAssignments": [
84
+ { "field": "DestinationLocationId", "valueRef": "Transfer_Destination" },
85
+ { "field": "IsReceived", "boolean": true },
86
+ { "field": "OwnerId", "valueRef": "$User.Id" },
87
+ { "field": "Product2Id", "valueRef": "Part_Transfers.Part_Number.value" },
88
+ { "field": "QuantityReceived", "valueRef": "Part_Transfers.Quantity.value" },
89
+ { "field": "QuantitySent", "valueRef": "Part_Transfers.Quantity.value" },
90
+ { "field": "ReceivedById", "valueRef": "$User.Id" }
91
+ ]
92
+ }
93
+ ]
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## How the converter wires it up
99
+
100
+ When `postScreen` is present:
101
+
102
+ - The **last screen's connector** points to the decision's `name` (or, if no decision, the first lookup, or the loop, or the first recordCreate — whichever is first in the chain).
103
+ - The decision emits `<decisions>` with one `<rules>` per branch. Each rule's `connector` targets `then`. The `defaultConnectorLabel` becomes the catch-all branch label (no connector means the flow ends on the default path).
104
+ - Each `recordLookups` emits its filter list, output assignments, and a `connector` to its `next`.
105
+ - The `loop` emits `<loops>` with `collectionReference`, `nextValueConnector` to its `next`. The "no more items" path falls through (no connector).
106
+ - Each `recordCreates` emits its input assignments and a `connector` back to the loop (so iteration continues). The loop's "default" (after items finish) is what naturally terminates the flow.
107
+ - All non-input variables in `postScreen.variables` are emitted alongside the three required `parentObjectType` / `parentRecordId` / `recordId` variables.
108
+
109
+ ## Spec → XML reference card
110
+
111
+ | Spec key | Emits |
112
+ |---|---|
113
+ | `valueRef` | `<elementReference>...</elementReference>` |
114
+ | `value` (string) | `<stringValue>...</stringValue>` |
115
+ | `boolean` | `<booleanValue>true|false</booleanValue>` |
116
+ | `number` | `<numberValue>...</numberValue>` |
117
+
118
+ Filter / decision-condition operators that have been seen in real flows: `EqualTo`, `NotEqualTo`, `GreaterThan`, `LessThan`, `IsNull`, `Contains`. The converter passes them through as-is — Salesforce will reject anything invalid.
119
+
120
+ ## Limitations
121
+
122
+ - Only one decision, one loop, and one chain of lookups+creates per spec. Real flows can have many; that's not in scope here.
123
+ - No `assignments` element (the Inventory_Transfer flow uses `recordLookups` outputAssignments instead, which we replicate).
124
+ - No formula resources or text templates.
125
+ - No nested loops, no decisions inside loops.
126
+
127
+ If you need any of the above, deploy what the skill produces and finish wiring in Flow Builder.
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: field-service-data-capture-form-designer-configure
3
+ description: "Design a Field Service Mobile Data Capture Flow from either a natural-language description OR a PDF/image of an existing paper form. Extracts field labels, types, required-state, and section structure into an intermediate JSON spec, confirms the plan with the user, then hands off to fs-data-capture-form-deployer for compile + deploy. Handles both input modes in one skill — prose ('build a Field Service form for asset inspection', 'make a DataCaptureFlow that asks the technician to…', 'create an inventory transfer form') and visual sources ('convert this PDF to a Data Capture Flow', 'make a Field Service form from this image', 'turn this paper form into a DataCaptureFlow'). Detects the input mode automatically from a .pdf/.png/.jpg/.jpeg path, else extracts from the prose. Do NOT use this skill to patch an already-deployed flow — that's fs-data-capture-form-editor."
4
+ user-invocable: false
5
+ metadata:
6
+ version: "1.0"
7
+ domains: ["Field Service"]
8
+ ---
9
+
10
+ # Design a Data Capture Form (from prose or from an image / PDF)
11
+
12
+ This skill produces an intermediate JSON spec from the user's input — a
13
+ natural-language description **or** a PDF/image of an existing form — gets the
14
+ user's approval on the plan, and then invokes `fs-data-capture-form-deployer` to
15
+ compile and deploy.
16
+
17
+ ## When this skill fires
18
+
19
+ The user asks for a Data Capture Flow / Field Service Mobile form. The input
20
+ arrives in one of two modes:
21
+
22
+ - **Prose mode** — the user describes the form in plain text with no attached file. Examples:
23
+ - "Create a data capture form for asset inspection that asks for asset id, condition rating, photos, and remarks."
24
+ - "Build a Field Service form for inventory transfer with parts repeater, source location, and destination dropdown."
25
+ - "Generate a DataCaptureFlow that captures three things: site name, contact info, and a notes field."
26
+ - **Image / PDF mode** — the user supplies a path to a `.pdf`, `.png`, `.jpg`, or `.jpeg` file. Examples:
27
+ - "Convert /tmp/inspection.pdf to a Data Capture Flow"
28
+ - "Build a Field Service form from this image: ~/Downloads/site-visit.png"
29
+ - "Turn this paper form into a DataCaptureFlow" (with attached image)
30
+
31
+ Detect the mode from the input: **if the user supplied a `.pdf` / `.png` / `.jpg` / `.jpeg` path, use image/PDF mode; otherwise use prose mode.** Everything after extraction (steps 2-6) is identical for both.
32
+
33
+ ## Workflow
34
+
35
+ ### 1. Read the source (mode-dependent)
36
+
37
+ **Prose mode — read the description carefully; don't fabricate fields.**
38
+ Extract only the fields the user actually mentioned. Don't invent extra fields based on what "usually goes on" an inspection form. If the user says "asks for asset id, condition rating, photos, and remarks", emit four fields, not eight.
39
+
40
+ If the user's description is too vague to produce a usable form ("build a form that captures stuff about a service appointment"), ask one or two targeted questions before extracting — what fields they want, whether there's a parent record, what should happen on submit. Don't guess.
41
+
42
+ Then apply the prose-evidence rules in [reference/extraction-from-prompt.md](reference/extraction-from-prompt.md).
43
+
44
+ **Image / PDF mode — read the file.**
45
+ Use the `Read` tool on the path the user gave you. PDFs and images are natively supported. If the PDF is more than 10 pages, ask the user which pages contain the form (the `Read` tool requires a `pages` parameter for large PDFs).
46
+
47
+ Then apply the control-evidence rules in [reference/extraction-from-image.md](reference/extraction-from-image.md).
48
+
49
+ ### 2. Extract the intermediate JSON
50
+
51
+ Apply every rule in the mode-appropriate extraction reference (from step 1). The output schema is defined by the **input contract of the build skill**:
52
+ - [field-types.md](../fs-data-capture-form-deployer/reference/field-types.md) — field type → component mapping, required Flow boilerplate, choice/repeater shapes, visibility rules.
53
+ - [post-screen-automation.md](../fs-data-capture-form-deployer/reference/post-screen-automation.md) — schema for the optional `postScreen` block.
54
+
55
+ Write the JSON to `/tmp/data-capture-spec.json`.
56
+
57
+ ### 3. Determine the desired outcome
58
+
59
+ A data capture form is a means, not an end. Before asking for approval, decide what should happen in Salesforce when the user submits the form:
60
+
61
+ - If the user explicitly says what to create/update ("create a ProductTransfer for each part"), OR the source/filename strongly implies an outcome (Inventory Transfer → ProductTransfer; Asset Inspection → WorkOrderLineItem) — emit a `postScreen` block with the named (or best-guess) object and field API names. When it's a best guess, list every `valueRef` / `field` in the confirmation step so the user can correct names.
62
+ - If the outcome is ambiguous AND the user gave no hint — surface the question in the confirmation step ("What should happen when this form is submitted?") with concrete options drawn from the form's domain.
63
+ - A screens-only flow with no `postScreen` is valid, but you must say so explicitly in the confirmation step.
64
+
65
+ See the mode-appropriate extraction reference for the full outcome-elicitation rules.
66
+
67
+ ### 4. Confirm with the user (mandatory gate)
68
+
69
+ Show the user what you plan to build before deploying. Use `AskUserQuestion` to gate the handoff to Build.
70
+
71
+ In the question body or surrounding text, plainly state:
72
+
73
+ 1. **The desired outcome.** What the flow does after the last screen — e.g. "Submitting the form will create a ProductTransfer per row in the Parts repeater" or "This flow only captures data — admin will wire up automation in Flow Builder." If a `postScreen` block was generated, list every Salesforce object name and every `field` API name it references. Object/field API names are the most common source of post-deploy errors.
74
+ 2. The `formTitle` and the proposed `<FlowApiName>` (PascalCase, no spaces).
75
+ 3. The number of screens and total fields (count repeater children too).
76
+ 4. Any visibility rules generated and the choice values they key off of.
77
+ 5. **Every field type, especially specialized ones, and the evidence it's based on.** For each `Signature`, `UploadFile`, `UploadImage`, `Images`, `Matrix`, `Address`, `Lookup`, `FileView`, or `Repeater` in the spec, name the field and the evidence — in prose mode the prose evidence ("user said 'parts repeater'", "user described a sign-here pad"); in image mode the visual evidence ("`damagePhoto` → UploadImage because the source has a camera-icon button"). These deploy as **real functional components** (`dcSignature`, `dcUpImage`, etc.) — so emitting them when the user only meant a text field (prose) or when you can only point to the field's *label* (image) is the most common extraction bug. If the matching control vocabulary / visual control isn't present, downgrade to `ShortText`/`LongText`/`Numeric` and call it out.
78
+ 6. **Lookup objects and FileView filenames.** For every `Lookup`, list the `lookupObject` (Salesforce object API name) and `lookupSearchFields` you chose. For every `FileView`, list the `fileName`. These names are common sources of post-deploy errors — surface them so the user can correct.
79
+ 7. Any fields that fell back to a labeled `dcTextInput` placeholder (only happens for `Lookup` with no `lookupObject` and `FileView` with no `fileName`).
80
+
81
+ Offer the user clear options:
82
+ - **Approve and deploy** — proceed to step 5.
83
+ - **Edit the spec first** — let them edit `/tmp/data-capture-spec.json` directly, then re-run from step 4.
84
+ - **Cancel** — stop without deploying.
85
+
86
+ Do not proceed to step 5 without explicit approval.
87
+
88
+ ### 5. Hand off to Build
89
+
90
+ Once approved, hand the approved spec to `fs-data-capture-form-deployer`. Pick a `<FlowApiName>` matching `^[A-Z][A-Za-z0-9_]*$` (default: PascalCase of `formTitle`), then follow that skill's workflow — it runs entirely over REST through the Codey runtime, with **no `sf` CLI, no scripts, and no `.flow-meta.xml`**:
91
+
92
+ 1. **Verify org auth** — [fs-data-capture-form-deployer/SKILL.md](../fs-data-capture-form-deployer/SKILL.md) §1 (a cheap `SELECT Id FROM Organization LIMIT 1` REST probe; the runtime resolves the connected org — this family does not manage aliases).
93
+ 2. **Build the Flow Metadata JSON inline** from the approved spec — deployer §3 + [reference/flow-metadata-json.md](../fs-data-capture-form-deployer/reference/flow-metadata-json.md). The agent assembles the `Metadata` object directly; there is no XML compile step.
94
+ 3. **Deploy** with a single `POST /services/data/vXX.0/tooling/sobjects/Flow` carrying `{ "FullName": "<FlowApiName>", "Metadata": { ... } }` — deployer §4.
95
+
96
+ After deploy, follow the reporting + error-handling steps in [fs-data-capture-form-deployer/SKILL.md](../fs-data-capture-form-deployer/SKILL.md) §5.
97
+
98
+ ### 6. Offer to attach the form to a parent record
99
+
100
+ After a successful deploy, the flow exists but is invisible from the Forms tab on any Service Appointment / Work Order. Ask the user whether they want it attached to a specific parent (the canonical "pending form" pattern). If yes, follow the attach steps in [fs-data-capture-form-deployer/SKILL.md](../fs-data-capture-form-deployer/SKILL.md) §6 — a single `POST /services/data/vXX.0/sobjects/DynamicDataCapture` (no scripts). For SA-context testing, attach to the SA's parent Work Order, not the SA itself — FSL Mobile reads Forms from the parent Work Order.
101
+
102
+ ## Out of scope
103
+
104
+ - Patching an already-deployed flow → `fs-data-capture-form-editor`.
105
+ - Hand-authoring patterns the converter doesn't generate (visual polish HTML, real `dcSignature`/`dcUpImage`, master-detail child records, supporting CustomObjects) → `fs-data-capture-reference` library skill.
106
+
107
+ ## Files in this skill
108
+
109
+ - `reference/extraction-from-prompt.md` — prose-evidence rules for picking field types from user descriptions, screen grouping, visibility rules, outcome-elicitation, validation checklist. Used in **prose mode**.
110
+ - `reference/extraction-from-image.md` — control-evidence rules for picking field types from rendered widgets, repeater extraction rules, screen grouping, visibility rules, outcome-elicitation, validation checklist. Used in **image / PDF mode**.