@uipath/maestro-builder-sdk 6.11.2 → 6.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/check.js +10 -24
- package/dist/core/hitl-answers.d.ts +19 -0
- package/dist/core/hitl-answers.js +4 -0
- package/dist/core/step-ports.d.ts +12 -0
- package/dist/core/step-ports.js +37 -0
- package/dist/registry/cache.d.ts +9 -0
- package/dist/registry/cache.js +9 -0
- package/dist/registry/path-cli.js +2 -2
- package/dist/registry/search-cli.js +6 -2
- package/dist/serialize.js +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ network calls. That is what `prepare` is for: it is the one verb that does talk
|
|
|
115
115
|
to the tenant. Run what `check` named, both fields at once:
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
|
|
118
|
+
uip maestro registry pull # once per machine: the connector library
|
|
119
119
|
|
|
120
120
|
npx flow-sdk registry prepare uipath-salesforce-slack --action send-message-to-user \
|
|
121
121
|
--resolve channel:profile.email=ada@example.com \
|
|
@@ -289,7 +289,7 @@ Keeping the names symbolic is what lets one flow move between connections: the
|
|
|
289
289
|
code says `slack`, and only `bindings.json` knows which Slack.
|
|
290
290
|
|
|
291
291
|
Discover ops and input shapes from the connector library that
|
|
292
|
-
`
|
|
292
|
+
`uip maestro registry pull` downloads and caches. A field the library does not
|
|
293
293
|
carry is connection-specific — that is the `prepare` case from the quick start.
|
|
294
294
|
|
|
295
295
|
The package also exposes the low-level materializer used by the UiPath CLI to
|
|
@@ -302,7 +302,7 @@ flow-registry-materialize \
|
|
|
302
302
|
--connectors ./connectors
|
|
303
303
|
```
|
|
304
304
|
|
|
305
|
-
Most callers want `
|
|
305
|
+
Most callers want `uip maestro registry pull`, which downloads the published
|
|
306
306
|
archive, verifies its checksum and then runs this transform. The low-level
|
|
307
307
|
command is for SDK development, build pipelines, and troubleshooting: it only
|
|
308
308
|
transforms local files that are already on disk.
|
|
@@ -322,7 +322,7 @@ The step-by-step authoring guides — `SKILL.md` for Flow, `SKILL-case.md`,
|
|
|
322
322
|
UiPath authoring skills catalog rather than here, so a coding agent and a human
|
|
323
323
|
read the same copy. The worked examples named by those guides travel with them.
|
|
324
324
|
|
|
325
|
-
The connector library is not bundled: `
|
|
325
|
+
The connector library is not bundled: `uip maestro registry pull` downloads it
|
|
326
326
|
and caches it per machine. The package does carry the curated overlay that pull
|
|
327
327
|
applies on top — corrections and the definitions the raw registry dump omits.
|
|
328
328
|
|
package/dist/check.js
CHANGED
|
@@ -11,8 +11,9 @@ import { isLookupToken, resolvedValue, unresolvedLookupMessage, } from './core/l
|
|
|
11
11
|
import { EVENT_FILTER_OPERATORS, readEventFilter, eventFilterProblem } from './event-filters.js';
|
|
12
12
|
import { extractRefs } from './core/expr-check.js';
|
|
13
13
|
import { bindingSelfNameMessage, bindingUndeclaredMessage, undeclaredBinding } from './core/binding-messages.js';
|
|
14
|
+
import { isAnswerField } from './core/hitl-answers.js';
|
|
14
15
|
import { hitlDerivesOutcomeHandles, hitlExitModel, hitlRoutesPerOutcome } from './core/hitl-routing.js';
|
|
15
|
-
import { declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
|
|
16
|
+
import { childStepLists, declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
|
|
16
17
|
import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
|
|
17
18
|
import { compareSchemaVersions, schemaVersionRefusal } from './schema-version.js';
|
|
18
19
|
import { prepareCommand, resolveFlagArg } from './core/cli-spelling.js';
|
|
@@ -1141,7 +1142,8 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
1141
1142
|
code: 'MOCK_HAS_NO_OUTPUT',
|
|
1142
1143
|
message: `Placeholder "${name}" publishes nothing, but "$vars.${name}${field ? '.' + field : ''}" reads it in "${step}". `
|
|
1143
1144
|
+ 'A mock() is a marker for a node that does not exist yet — its output is null at run time, always. '
|
|
1144
|
-
+ '
|
|
1145
|
+
+ 'Keep the placeholder while the real node does not exist, and have the reader use a value you supply instead (a flow input, as example/ClaimScaffold.flow.ts does). '
|
|
1146
|
+
+ 'Replace the placeholder only with the real node, once `registry search` finds it; a script returning fixed values is not the real node.',
|
|
1145
1147
|
step,
|
|
1146
1148
|
});
|
|
1147
1149
|
continue;
|
|
@@ -1644,20 +1646,7 @@ function checkLoopListEnvelope(loop, connectors, opts, diags) {
|
|
|
1644
1646
|
}
|
|
1645
1647
|
/** True if any step on THIS flow's own tree is a `.return()`. */
|
|
1646
1648
|
function hasReturn(steps) {
|
|
1647
|
-
|
|
1648
|
-
if (s.kind === 'return')
|
|
1649
|
-
return true;
|
|
1650
|
-
if (s.kind === 'branch' && (hasReturn(s.then) || hasReturn(s.otherwise)))
|
|
1651
|
-
return true;
|
|
1652
|
-
if (s.kind === 'switch'
|
|
1653
|
-
&& (s.cases.some((c) => hasReturn(c.body)) || hasReturn(s.default ?? [])))
|
|
1654
|
-
return true;
|
|
1655
|
-
if (s.kind === 'parallel' && s.arms.some(hasReturn))
|
|
1656
|
-
return true;
|
|
1657
|
-
if ((s.kind === 'loop' || s.kind === 'doWhile') && hasReturn(s.body))
|
|
1658
|
-
return true;
|
|
1659
|
-
}
|
|
1660
|
-
return false;
|
|
1649
|
+
return steps.some((s) => s.kind === 'return' || childStepLists(s).some(hasReturn));
|
|
1661
1650
|
}
|
|
1662
1651
|
/**
|
|
1663
1652
|
* Closest of `candidates` to `name`: same word ignoring case, one contained in
|
|
@@ -4777,9 +4766,9 @@ function checkHitl(step, inputs, diags) {
|
|
|
4777
4766
|
+ `gets a text box and the value comes back as a string. Valid: `
|
|
4778
4767
|
+ `${FORM_FIELD_TYPES.join(', ')}.`, nearest !== undefined ? `type: '${nearest}'` : `type: 'text'`);
|
|
4779
4768
|
}
|
|
4769
|
+
if (isAnswerField(f))
|
|
4770
|
+
answers++; // an `output`, or an `inOut` whose reviewed value comes back
|
|
4780
4771
|
if (f?.direction === 'input' || f?.direction === 'inOut') {
|
|
4781
|
-
if (f.direction === 'inOut')
|
|
4782
|
-
answers++; // the reviewed value comes back
|
|
4783
4772
|
const value = f.value;
|
|
4784
4773
|
if (value === undefined || value === null) {
|
|
4785
4774
|
at('HITL_FIELD_NO_VALUE', `Human task "${step}" shows the form field "${id}" to the reviewer but gives it no value, `
|
|
@@ -4800,10 +4789,7 @@ function checkHitl(step, inputs, diags) {
|
|
|
4800
4789
|
+ `Compute it in a script step first and point the field at that step's output.`, `value: out('<scriptStep>')`);
|
|
4801
4790
|
}
|
|
4802
4791
|
}
|
|
4803
|
-
else if (f?.direction
|
|
4804
|
-
answers++;
|
|
4805
|
-
}
|
|
4806
|
-
else {
|
|
4792
|
+
else if (f?.direction !== 'output') {
|
|
4807
4793
|
at('HITL_FIELD_DIRECTION', `Human task "${step}" gives the form field "${id}" the direction `
|
|
4808
4794
|
+ `${JSON.stringify(f?.direction)}. A field is shown to the `
|
|
4809
4795
|
+ `reviewer ('input'), filled in by them ('output'), or pre-filled and editable ('inOut'); `
|
|
@@ -4926,7 +4912,7 @@ function checkHitlRead(name, field, rest, form, step, diags) {
|
|
|
4926
4912
|
if (answer === 'Action')
|
|
4927
4913
|
return; // which outcome was pressed.
|
|
4928
4914
|
const answers = (form?.fields ?? [])
|
|
4929
|
-
.filter((f) => f
|
|
4915
|
+
.filter((f) => isAnswerField(f) && typeof f?.id === 'string')
|
|
4930
4916
|
.map((f) => f.id);
|
|
4931
4917
|
if (answers.includes(answer))
|
|
4932
4918
|
return;
|
|
@@ -4938,7 +4924,7 @@ function checkHitlRead(name, field, rest, form, step, diags) {
|
|
|
4938
4924
|
level: 'error',
|
|
4939
4925
|
code: 'HITL_READ_UNKNOWN_FIELD',
|
|
4940
4926
|
message: `Human task "${name}" has no answer "${answer}" (read as "$vars.${name}.output.${answer}" in `
|
|
4941
|
-
+ `"${step}"). Its result carries only the fields the reviewer FILLS IN`
|
|
4927
|
+
+ `"${step}"). Its result carries only the fields the reviewer FILLS IN or EDITS`
|
|
4942
4928
|
+ `${answers.length > 0 ? ` (${answers.join(', ')})` : ' (it declares none)'} plus "Action". `
|
|
4943
4929
|
+ (shown.includes(answer)
|
|
4944
4930
|
? `"${answer}" is a field the reviewer only reads, so it is not part of the answer — read the `
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which form fields of a human task come back in its answer object — the one
|
|
3
|
+
* rule `serialize` (the emitted `outputs.output.properties`) and `check` (the
|
|
4
|
+
* answer count and every `out('<task>', '<field>')` read) all use, so they
|
|
5
|
+
* cannot drift. They did drift (UV-16855): `serialize` emitted `inOut` fields
|
|
6
|
+
* as answers and `check` counted them as answers, but the read check listed
|
|
7
|
+
* `output` fields only, so the documented read of an editable field —
|
|
8
|
+
* `out('review', 'comment')` for `{ id: 'comment', direction: 'inOut', … }` —
|
|
9
|
+
* failed `check` and blocked `compile`.
|
|
10
|
+
*
|
|
11
|
+
* - `output` — the reviewer fills it in; the value comes back.
|
|
12
|
+
* - `inOut` — pre-filled and editable; the (possibly changed) value comes back.
|
|
13
|
+
* - `input` — shown only; NOT an answer. Read the value bound to it instead.
|
|
14
|
+
*/
|
|
15
|
+
export type AnswerDirection = 'output' | 'inOut';
|
|
16
|
+
/** True when the field's value comes back in the task's answer object. */
|
|
17
|
+
export declare function isAnswerField(field: {
|
|
18
|
+
direction?: unknown;
|
|
19
|
+
} | null | undefined): boolean;
|
|
@@ -42,4 +42,16 @@ export declare function hasExits(r: DeclaredExit[] | NoExits): r is DeclaredExit
|
|
|
42
42
|
* `.parallel` join waiting: a terminate ends the run, join included.
|
|
43
43
|
*/
|
|
44
44
|
export declare function stopsAtEnd(steps: readonly Step[]): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The step lists nested DIRECTLY inside `step` — the bodies a walk over this
|
|
47
|
+
* flow's own tree must descend into. Exhaustive over `Step['kind']`, so a new
|
|
48
|
+
* container kind fails to compile here instead of being silently skipped by
|
|
49
|
+
* every walker. That is how `check`'s return scan came to miss `.stepSwitch`
|
|
50
|
+
* arms and `.stepToList` / `.onError` bodies, and warned NO_RETURN on flows
|
|
51
|
+
* whose every path ends in `.return()` (UV-16855).
|
|
52
|
+
*
|
|
53
|
+
* A subflow's child flow is deliberately NOT a child here: it is another
|
|
54
|
+
* flow's tree, and its returns say nothing about whether THIS flow ends.
|
|
55
|
+
*/
|
|
56
|
+
export declare function childStepLists(step: Step): readonly Step[][];
|
|
45
57
|
export {};
|
package/dist/core/step-ports.js
CHANGED
|
@@ -107,3 +107,40 @@ export function stopsAtEnd(steps) {
|
|
|
107
107
|
|| (st.kind === 'switch' && st.default !== undefined && has(st.default, kinds)));
|
|
108
108
|
return has(steps, new Set(['return'])) && !has(steps, new Set(['terminate', 'break']));
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The step lists nested DIRECTLY inside `step` — the bodies a walk over this
|
|
112
|
+
* flow's own tree must descend into. Exhaustive over `Step['kind']`, so a new
|
|
113
|
+
* container kind fails to compile here instead of being silently skipped by
|
|
114
|
+
* every walker. That is how `check`'s return scan came to miss `.stepSwitch`
|
|
115
|
+
* arms and `.stepToList` / `.onError` bodies, and warned NO_RETURN on flows
|
|
116
|
+
* whose every path ends in `.return()` (UV-16855).
|
|
117
|
+
*
|
|
118
|
+
* A subflow's child flow is deliberately NOT a child here: it is another
|
|
119
|
+
* flow's tree, and its returns say nothing about whether THIS flow ends.
|
|
120
|
+
*/
|
|
121
|
+
export function childStepLists(step) {
|
|
122
|
+
switch (step.kind) {
|
|
123
|
+
case 'branch':
|
|
124
|
+
return [step.then, step.otherwise];
|
|
125
|
+
case 'switch':
|
|
126
|
+
return [...step.cases.map((c) => c.body), ...(step.default ? [step.default] : [])];
|
|
127
|
+
case 'stepSwitch':
|
|
128
|
+
return step.cases.map((c) => c.body);
|
|
129
|
+
case 'loop':
|
|
130
|
+
case 'doWhile':
|
|
131
|
+
case 'stepToList':
|
|
132
|
+
return [step.body];
|
|
133
|
+
case 'parallel':
|
|
134
|
+
return step.arms;
|
|
135
|
+
case 'action':
|
|
136
|
+
case 'break':
|
|
137
|
+
case 'terminate':
|
|
138
|
+
case 'stepToRef':
|
|
139
|
+
case 'return':
|
|
140
|
+
return [];
|
|
141
|
+
default: {
|
|
142
|
+
const unhandled = step;
|
|
143
|
+
throw new Error(`childStepLists: unhandled step kind ${JSON.stringify(unhandled.kind)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
package/dist/registry/cache.d.ts
CHANGED
|
@@ -21,6 +21,15 @@
|
|
|
21
21
|
export declare const LIBRARY_JSON_DIR = "library-json";
|
|
22
22
|
export declare const LIBRARY_MARKDOWN_DIR = "library-md";
|
|
23
23
|
export declare const CURRENT_LINK = "current";
|
|
24
|
+
/**
|
|
25
|
+
* The command a message tells a person or agent to run when the cache is
|
|
26
|
+
* empty. It is `uip`, not `npx flow-sdk registry pull`: `uip maestro registry
|
|
27
|
+
* pull` runs this package's pull and fills the same cache, and it is the one
|
|
28
|
+
* command the authoring skill teaches. Each message used to spell the command
|
|
29
|
+
* out by hand, so they kept naming the SDK's own entry point after the skill
|
|
30
|
+
* moved to `uip`. Name it here once.
|
|
31
|
+
*/
|
|
32
|
+
export declare const PULL_COMMAND = "uip maestro registry pull";
|
|
24
33
|
/**
|
|
25
34
|
* Root of the library cache. `UIP_FLOW_SDK_LIBRARY_CACHE` overrides it.
|
|
26
35
|
*
|
package/dist/registry/cache.js
CHANGED
|
@@ -24,6 +24,15 @@ import { join } from "node:path";
|
|
|
24
24
|
export const LIBRARY_JSON_DIR = "library-json";
|
|
25
25
|
export const LIBRARY_MARKDOWN_DIR = "library-md";
|
|
26
26
|
export const CURRENT_LINK = "current";
|
|
27
|
+
/**
|
|
28
|
+
* The command a message tells a person or agent to run when the cache is
|
|
29
|
+
* empty. It is `uip`, not `npx flow-sdk registry pull`: `uip maestro registry
|
|
30
|
+
* pull` runs this package's pull and fills the same cache, and it is the one
|
|
31
|
+
* command the authoring skill teaches. Each message used to spell the command
|
|
32
|
+
* out by hand, so they kept naming the SDK's own entry point after the skill
|
|
33
|
+
* moved to `uip`. Name it here once.
|
|
34
|
+
*/
|
|
35
|
+
export const PULL_COMMAND = "uip maestro registry pull";
|
|
27
36
|
/**
|
|
28
37
|
* Root of the library cache. `UIP_FLOW_SDK_LIBRARY_CACHE` overrides it.
|
|
29
38
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reportResult } from '../cli-result.js';
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { CURRENT_LINK, currentEntrySha, libraryCacheRoot, resolveCachedLibrary, resolveCachedMarkdown, } from "./cache.js";
|
|
3
|
+
import { CURRENT_LINK, PULL_COMMAND, currentEntrySha, libraryCacheRoot, resolveCachedLibrary, resolveCachedMarkdown, } from "./cache.js";
|
|
4
4
|
/**
|
|
5
5
|
* Say where the connector library is.
|
|
6
6
|
*
|
|
@@ -34,7 +34,7 @@ export async function run(argv) {
|
|
|
34
34
|
const single = (field, value) => {
|
|
35
35
|
reportResult({ [field]: value ?? null });
|
|
36
36
|
if (!value) {
|
|
37
|
-
console.error(
|
|
37
|
+
console.error(`No connector library in the cache yet. Run \`${PULL_COMMAND}\`.`);
|
|
38
38
|
return 1;
|
|
39
39
|
}
|
|
40
40
|
console.log(value);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reportResult } from '../cli-result.js';
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
|
-
import { resolveLibraryDir } from "./cache.js";
|
|
3
|
+
import { PULL_COMMAND, resolveLibraryDir } from "./cache.js";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
export const DEFAULT_SEARCH_LIMIT = 20;
|
|
6
6
|
const USAGE = "Usage: flow-sdk registry search [query] [--library <dir>] [--library-md <dir>] [--connector <key>] [--limit <n>]";
|
|
@@ -52,7 +52,7 @@ export async function searchRegistryOperations(options) {
|
|
|
52
52
|
content = await readFile(indexPath, "utf-8");
|
|
53
53
|
}
|
|
54
54
|
catch {
|
|
55
|
-
throw new Error(`Could not read ${indexPath}. Run
|
|
55
|
+
throw new Error(`Could not read ${indexPath}. Run \`${PULL_COMMAND}\`, or point` +
|
|
56
56
|
" --library at an extracted connector library.");
|
|
57
57
|
}
|
|
58
58
|
let parsed;
|
|
@@ -120,6 +120,10 @@ export async function run(argv) {
|
|
|
120
120
|
// verbs defaulted it was the inconsistency an author hit first.
|
|
121
121
|
const libraryPath = resolveLibraryDir(value(argv, "--library"));
|
|
122
122
|
if (!libraryPath) {
|
|
123
|
+
// Say why. A bare usage line here read as "no match" to an agent deciding
|
|
124
|
+
// between a connector and http(): it took the failed search for a miss.
|
|
125
|
+
console.error(`No connector library is cached. Run \`${PULL_COMMAND}\`, or pass` +
|
|
126
|
+
" --library <dir>.");
|
|
123
127
|
console.error(USAGE);
|
|
124
128
|
return 2;
|
|
125
129
|
}
|
package/dist/serialize.js
CHANGED
|
@@ -14,6 +14,7 @@ import { Expr, toExpr, SCHEDULE_PRESETS, DELAY_PRESETS, parseIxpProjectType, fla
|
|
|
14
14
|
import { FlowAction, FlowTrigger } from './core/node-classes.js';
|
|
15
15
|
import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
|
|
16
16
|
import { dataFabricUnknownInputs } from './core/typed-raw-node.js';
|
|
17
|
+
import { isAnswerField } from './core/hitl-answers.js';
|
|
17
18
|
import { BindingRefusal, GUID_RE, bindingSelfNameMessage, bindingUndeclaredMessage, undeclaredBinding } from './core/binding-messages.js';
|
|
18
19
|
import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitModel, hitlExitViolation, outcomeSlug } from './core/hitl-routing.js';
|
|
19
20
|
import { declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
|
|
@@ -2800,7 +2801,7 @@ function hitlInputs(inputs, nodeId, flowId, label, rename) {
|
|
|
2800
2801
|
const properties = {};
|
|
2801
2802
|
for (const f of inputs?.fields ?? []) {
|
|
2802
2803
|
// inOut fields land in the answers too — their reviewed value flows back.
|
|
2803
|
-
if (f
|
|
2804
|
+
if (!isAnswerField(f))
|
|
2804
2805
|
continue;
|
|
2805
2806
|
properties[f.id] = { ...FORM_FIELD_JSON_TYPE[f.type] };
|
|
2806
2807
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.11.
|
|
3
|
+
"version": "6.11.4",
|
|
4
4
|
"description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.uipath.com/maestro",
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
"@types/node": "^22.7.0",
|
|
93
93
|
"esbuild": "^0.28.1"
|
|
94
94
|
},
|
|
95
|
-
"gitref": "
|
|
95
|
+
"gitref": "8c18e5efb6f8dd4b2599f9591cabdff42feaf275"
|
|
96
96
|
}
|