@uipath/maestro-builder-sdk 6.9.4 → 6.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -10
- package/dist/api-index.md +15 -15
- package/dist/api-members.md +14 -14
- package/dist/bpmn/check-cli.js +2 -0
- package/dist/bpmn/compile-cli.js +3 -1
- package/dist/bpmn/decompile-cli.js +3 -1
- package/dist/bpmn/merge-cli.js +3 -1
- package/dist/bpmn/tidy-cli.js +3 -0
- package/dist/case/check-cli.js +2 -0
- package/dist/case/compile-cli.js +3 -1
- package/dist/case/decompile-cli.js +3 -0
- package/dist/case/merge-cli.js +3 -1
- package/dist/check-cli.js +2 -0
- package/dist/check.js +2 -2
- package/dist/cli/commands/bpmn.js +16 -10
- package/dist/cli/commands/case.js +16 -10
- package/dist/cli/commands/flow.d.ts +1 -1
- package/dist/cli/commands/flow.js +45 -21
- package/dist/cli/commands/registry.js +11 -3
- package/dist/cli/common.d.ts +41 -0
- package/dist/cli/common.js +97 -0
- package/dist/cli/index.js +40 -2
- package/dist/cli-result.d.ts +22 -0
- package/dist/cli-result.js +31 -0
- package/dist/compile-cli.js +12 -0
- package/dist/core/actions.d.ts +1 -2
- package/dist/core/actions.js +1 -2
- package/dist/core/cli-spelling.d.ts +5 -3
- package/dist/core/cli-spelling.js +8 -4
- package/dist/core/lookups.js +1 -1
- package/dist/decompile-cli.js +3 -0
- package/dist/merge-cli.js +3 -1
- package/dist/registry/generators/markdown/sections/choosing-object.js +1 -1
- package/dist/registry/generators/markdown/sections/example.js +2 -2
- package/dist/registry/generators/markdown/sections/lookups.js +1 -1
- package/dist/registry/generators/markdown/sections/schema-dynamic.js +3 -3
- package/dist/registry/library-build/cli.js +3 -0
- package/dist/registry/materialize-cli.js +7 -0
- package/dist/registry/path-cli.js +14 -7
- package/dist/registry/prepare/messages.js +4 -4
- package/dist/registry/prepare/pipeline.d.ts +2 -0
- package/dist/registry/prepare/pipeline.js +4 -2
- package/dist/registry/prepare-cli.js +6 -3
- package/dist/registry/pull-cli.js +10 -1
- package/dist/registry/search-cli.js +2 -0
- package/package.json +7 -2
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Option } from 'commander';
|
|
2
|
+
import { addValue, emitOnlyEnabled, inferCheckMode, invoke, loadTool, namedOrLegacySecond, retiredCompiledOption, refuse } from '../common.js';
|
|
3
|
+
/** The retired compiled check's flags: `[commander flags, option key, description]`. One table, so hiding and warning cannot drift. */
|
|
4
|
+
const RETIRED_COMPILED_CHECK_FLAGS = [
|
|
5
|
+
['--uip', 'uip', 'retired: resolve missing schemas with the UiPath CLI'],
|
|
6
|
+
['--max-errors <count>', 'maxErrors', 'retired: stop after this many compiled-check errors'],
|
|
7
|
+
['--script-determinism', 'scriptDeterminism', 'retired: check script blocks for non-deterministic calls'],
|
|
8
|
+
['--quiet', 'quiet', 'retired: suppress warnings and information'],
|
|
9
|
+
['--debug-internal', 'debugInternal', 'retired: include internal compile context'],
|
|
10
|
+
['--dump-ir', 'dumpIr', 'retired: print the generated intermediate representation'],
|
|
11
|
+
];
|
|
12
|
+
function retiredFlagsPassed(options) {
|
|
13
|
+
return RETIRED_COMPILED_CHECK_FLAGS
|
|
14
|
+
.filter(([, key]) => options[key] !== undefined && options[key] !== false)
|
|
15
|
+
.map(([flags]) => flags.split(' ')[0]);
|
|
16
|
+
}
|
|
2
17
|
export function registerFlowCommands(program) {
|
|
3
18
|
const flow = program.command('flow').description('Build and check Flow artifacts.');
|
|
4
19
|
flow.command('compile')
|
|
@@ -19,24 +34,21 @@ export function registerFlowCommands(program) {
|
|
|
19
34
|
argv.push('--no-check');
|
|
20
35
|
await invoke('flow compile', () => loadTool(import.meta.url, '../../compile-cli.js'), argv);
|
|
21
36
|
});
|
|
22
|
-
flow.command('check')
|
|
23
|
-
.description('Check authored TypeScript
|
|
24
|
-
.argument('<input>', '
|
|
37
|
+
const check = flow.command('check')
|
|
38
|
+
.description('Check authored TypeScript. Check a compiled .flow with `uip maestro flow validate`.')
|
|
39
|
+
.argument('<input>', 'a .flow.ts path or bare name')
|
|
25
40
|
.option('--source', 'check authored TypeScript')
|
|
26
|
-
.
|
|
41
|
+
.addOption(retiredCompiledOption())
|
|
27
42
|
.option('--library <dir>', 'connector library directory')
|
|
28
|
-
.option('--connectors-local <dir>', 'connection-resolved connector overlay')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.option('--debug-internal', 'include internal compile context')
|
|
35
|
-
.option('--dump-ir', 'print the generated intermediate representation')
|
|
43
|
+
.option('--connectors-local <dir>', 'connection-resolved connector overlay');
|
|
44
|
+
// Hidden, not removed: scripts that pass these keep parsing.
|
|
45
|
+
for (const [flags, , description] of RETIRED_COMPILED_CHECK_FLAGS) {
|
|
46
|
+
check.addOption(new Option(flags, description).hideHelp());
|
|
47
|
+
}
|
|
48
|
+
check
|
|
36
49
|
.action(async (input, options) => {
|
|
37
50
|
if (emitOnlyEnabled()) {
|
|
38
|
-
|
|
39
|
-
process.exitCode = 2;
|
|
51
|
+
refuse('flow-sdk flow check: disabled by emit-only mode; use `uip maestro flow validate` or `uip maestro flow debug`');
|
|
40
52
|
return;
|
|
41
53
|
}
|
|
42
54
|
let mode;
|
|
@@ -44,11 +56,16 @@ export function registerFlowCommands(program) {
|
|
|
44
56
|
mode = inferCheckMode('flow', input, options.source === true, options.compiled === true);
|
|
45
57
|
}
|
|
46
58
|
catch (error) {
|
|
47
|
-
|
|
48
|
-
process.exitCode = 2;
|
|
59
|
+
refuse(`flow-sdk flow check: ${error instanceof Error ? error.message : String(error)}`);
|
|
49
60
|
return;
|
|
50
61
|
}
|
|
51
62
|
if (mode === 'source') {
|
|
63
|
+
const ignored = retiredFlagsPassed(options);
|
|
64
|
+
// Not under `--quiet`: a caller asking for less output (an older
|
|
65
|
+
// `uip` still forwards it) must not get a new line because of it.
|
|
66
|
+
if (ignored.length > 0 && options.quiet !== true) {
|
|
67
|
+
console.error(`flow-sdk flow check: ignoring ${ignored.join(', ')} (used only by the retired compiled check)`);
|
|
68
|
+
}
|
|
52
69
|
const argv = [input];
|
|
53
70
|
addValue(argv, '--library', options.library);
|
|
54
71
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
@@ -63,11 +80,10 @@ export function registerFlowCommands(program) {
|
|
|
63
80
|
// and every current authoring flow uses — this path already refused, with the same two
|
|
64
81
|
// suggestions repeated here. What is checked at author time is `check.ts`, reached above by
|
|
65
82
|
// the `source` arm, and that is untouched.
|
|
66
|
-
|
|
83
|
+
refuse('flow-sdk flow check: checking a COMPILED .flow is no longer supported here. ' +
|
|
67
84
|
'Use `uip maestro flow validate <file.flow>` for the product static check, or ' +
|
|
68
85
|
'`uip maestro flow debug` / `flow-debug <file.flow>` to run it. ' +
|
|
69
86
|
'Authoring-time checks still work on a .flow.ts source (--source).');
|
|
70
|
-
process.exitCode = 2;
|
|
71
87
|
});
|
|
72
88
|
flow.command('decompile')
|
|
73
89
|
.description('Convert a .flow artifact to authored TypeScript.')
|
|
@@ -88,11 +104,19 @@ export function registerFlowCommands(program) {
|
|
|
88
104
|
});
|
|
89
105
|
flow.command('merge')
|
|
90
106
|
.description('Merge an edited flow with its original artifact.')
|
|
91
|
-
.argument('<original>', 'original .flow path')
|
|
92
107
|
.argument('<edited>', 'edited .flow path')
|
|
108
|
+
.option('--original <file>', '(required) original .flow path, the artifact to merge into')
|
|
93
109
|
.option('-o, --output <file>', 'merged output path')
|
|
94
110
|
.option('--baseline <file>', 'compiled pristine decompile')
|
|
95
|
-
.
|
|
111
|
+
.allowExcessArguments()
|
|
112
|
+
.action(async (_edited, options, command) => {
|
|
113
|
+
const pair = namedOrLegacySecond(command, {
|
|
114
|
+
label: 'flow merge', flag: '--original', named: options.original, legacyNamedFirst: true,
|
|
115
|
+
usage: 'flow merge <edited> --original <file>',
|
|
116
|
+
});
|
|
117
|
+
if (!pair)
|
|
118
|
+
return;
|
|
119
|
+
const [edited, original] = pair;
|
|
96
120
|
const argv = [original, edited];
|
|
97
121
|
addValue(argv, '-o', options.output);
|
|
98
122
|
addValue(argv, '--baseline', options.baseline);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addValue, invoke, loadTool } from '../common.js';
|
|
1
|
+
import { addValue, invoke, loadTool, namedOrLegacySecond } from '../common.js';
|
|
2
2
|
/** Commander hands a repeatable option one value at a time. */
|
|
3
3
|
function collect(value, previous) {
|
|
4
4
|
return [...previous, value];
|
|
@@ -124,7 +124,8 @@ export function registerRegistryCommands(program) {
|
|
|
124
124
|
family.command('prepare')
|
|
125
125
|
.description("Resolve one operation's schema against a live connection into ./connectors-local.")
|
|
126
126
|
.argument('<connector-key>', 'connector key, e.g. uipath-salesforce')
|
|
127
|
-
.
|
|
127
|
+
.option('--action <name>', '(required) operation to resolve, e.g. InsertRecord')
|
|
128
|
+
.allowExcessArguments()
|
|
128
129
|
// Optional: without one the command discovers the connection itself from
|
|
129
130
|
// `uip is connections list` and writes both keys into bindings.json.
|
|
130
131
|
.option('--connection-id <id>', 'connection to read the schema through')
|
|
@@ -158,7 +159,14 @@ export function registerRegistryCommands(program) {
|
|
|
158
159
|
.option('--refresh-lookups', 're-resolve lookups already recorded in resolutions.json')
|
|
159
160
|
.option('--source <flow.ts>', 'the flow whose import to repoint at the prepared descriptor')
|
|
160
161
|
.option('--no-source-rewrite', 'print the import line instead of editing the source')
|
|
161
|
-
.action(async (
|
|
162
|
+
.action(async (_connectorKey, options, command) => {
|
|
163
|
+
const pair = namedOrLegacySecond(command, {
|
|
164
|
+
label: 'registry prepare', flag: '--action', named: options.action, legacyNamedFirst: false,
|
|
165
|
+
usage: 'registry prepare <connector-key> --action <name>',
|
|
166
|
+
});
|
|
167
|
+
if (!pair)
|
|
168
|
+
return;
|
|
169
|
+
const [connectorKey, action] = pair;
|
|
162
170
|
const argv = [connectorKey, action];
|
|
163
171
|
addValue(argv, '--connection-id', options.connectionId);
|
|
164
172
|
addValue(argv, '--connection', options.connection);
|
package/dist/cli/common.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Command, Option } from 'commander';
|
|
1
2
|
export type ToolRun = (argv: string[]) => Promise<number> | number;
|
|
2
3
|
export declare function loadTool(baseUrl: string, relativePath: string): Promise<{
|
|
3
4
|
run: ToolRun;
|
|
@@ -5,6 +6,24 @@ export declare function loadTool(baseUrl: string, relativePath: string): Promise
|
|
|
5
6
|
export declare function invoke(label: string, load: () => Promise<{
|
|
6
7
|
run: ToolRun;
|
|
7
8
|
}>, argv: string[]): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Refuse the verb before any tool runs: the message on stderr, the exit code
|
|
11
|
+
* (2, a usage error or blocked mode, unless given), and the message as the
|
|
12
|
+
* `--json` object's `error`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function refuse(message: string, exitCode?: number): void;
|
|
15
|
+
/** Record why the verb failed before any tool ran, for the `--json` object. */
|
|
16
|
+
export declare function recordJsonError(message: string): void;
|
|
17
|
+
/** Turn `--json` on for this run (the umbrella's `preAction` hook). */
|
|
18
|
+
export declare function requestJsonResult(): void;
|
|
19
|
+
export declare function jsonResultRequested(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Print the verb's result as one JSON object on stdout: `ok` (the exit code
|
|
22
|
+
* was 0) plus whatever the tool reported. Printed even when the verb refused
|
|
23
|
+
* before reaching a tool (a usage error, emit-only mode), so a `--json` caller
|
|
24
|
+
* always gets one object to parse.
|
|
25
|
+
*/
|
|
26
|
+
export declare function emitJsonResult(): void;
|
|
8
27
|
export declare function addValue(argv: string[], flag: string, value: unknown): void;
|
|
9
28
|
/**
|
|
10
29
|
* Is emit-only mode on for the PROJECT containing `cwd`?
|
|
@@ -28,3 +47,25 @@ export declare function addValue(argv: string[], flag: string, value: unknown):
|
|
|
28
47
|
export declare function emitOnlyEnabled(cwd?: string, env?: NodeJS.ProcessEnv): boolean;
|
|
29
48
|
export type CheckMode = 'source' | 'compiled';
|
|
30
49
|
export declare function inferCheckMode(family: 'flow' | 'case' | 'bpmn', input: string, source: boolean, compiled: boolean): CheckMode;
|
|
50
|
+
/**
|
|
51
|
+
* `--compiled` on `<family> check`: hidden from `--help`, still accepted so a
|
|
52
|
+
* script that passes it gets the redirect to `uip maestro <family> validate`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function retiredCompiledOption(): Option;
|
|
55
|
+
/**
|
|
56
|
+
* The primary positional and a named second value (`--original`, `--action`),
|
|
57
|
+
* also accepting the deprecated two-positional form with a warning.
|
|
58
|
+
* `legacyNamedFirst` says where the named value sat in that form: first for
|
|
59
|
+
* merge (`<original> <edited>`), second for prepare (`<key> <action>`). The
|
|
60
|
+
* verb must call `allowExcessArguments()` so the legacy value reaches
|
|
61
|
+
* `command.args`.
|
|
62
|
+
*
|
|
63
|
+
* Returns `[primary, named]`, or `null` after reporting a usage error (exit 2).
|
|
64
|
+
*/
|
|
65
|
+
export declare function namedOrLegacySecond(command: Command, spec: {
|
|
66
|
+
label: string;
|
|
67
|
+
flag: string;
|
|
68
|
+
named: string | undefined;
|
|
69
|
+
legacyNamedFirst: boolean;
|
|
70
|
+
usage: string;
|
|
71
|
+
}): [string, string] | null;
|
package/dist/cli/common.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { Option } from 'commander';
|
|
3
4
|
export function loadTool(baseUrl, relativePath) {
|
|
4
5
|
return import(new URL(relativePath, baseUrl).href);
|
|
5
6
|
}
|
|
6
7
|
export async function invoke(label, load, argv) {
|
|
8
|
+
// In `--json` mode stdout carries exactly one JSON object, printed by
|
|
9
|
+
// `emitJsonResult` once the verb is done. The tool's own human lines go to
|
|
10
|
+
// stderr meanwhile, so they are still seen but never mixed into it.
|
|
11
|
+
const restore = jsonResultRequested() ? routeStdoutToStderr() : () => { };
|
|
7
12
|
try {
|
|
8
13
|
const code = await (await load()).run(argv);
|
|
9
14
|
if (code !== 0)
|
|
@@ -12,8 +17,63 @@ export async function invoke(label, load, argv) {
|
|
|
12
17
|
catch (error) {
|
|
13
18
|
const message = error instanceof Error ? error.message : String(error);
|
|
14
19
|
console.error(`flow-sdk ${label}: ${message}`);
|
|
20
|
+
resultSlot().fields.error ??= message;
|
|
15
21
|
process.exitCode = 1;
|
|
16
22
|
}
|
|
23
|
+
finally {
|
|
24
|
+
restore();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The slot `src/cli-result.ts` writes (`reportResult`). Read here through the
|
|
29
|
+
* same `Symbol.for` key, since `dist/cli/` and `dist/` are separate builds.
|
|
30
|
+
*/
|
|
31
|
+
const RESULT_SLOT = Symbol.for('uipath.maestro-builder-sdk.cli-result');
|
|
32
|
+
function resultSlot() {
|
|
33
|
+
const global = globalThis;
|
|
34
|
+
global[RESULT_SLOT] ??= { json: false, fields: {} };
|
|
35
|
+
return global[RESULT_SLOT];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Refuse the verb before any tool runs: the message on stderr, the exit code
|
|
39
|
+
* (2, a usage error or blocked mode, unless given), and the message as the
|
|
40
|
+
* `--json` object's `error`.
|
|
41
|
+
*/
|
|
42
|
+
export function refuse(message, exitCode = 2) {
|
|
43
|
+
console.error(message);
|
|
44
|
+
recordJsonError(message);
|
|
45
|
+
process.exitCode = exitCode;
|
|
46
|
+
}
|
|
47
|
+
/** Record why the verb failed before any tool ran, for the `--json` object. */
|
|
48
|
+
export function recordJsonError(message) {
|
|
49
|
+
resultSlot().fields.error ??= message.replace(/^error: /, '');
|
|
50
|
+
}
|
|
51
|
+
/** Turn `--json` on for this run (the umbrella's `preAction` hook). */
|
|
52
|
+
export function requestJsonResult() {
|
|
53
|
+
resultSlot().json = true;
|
|
54
|
+
}
|
|
55
|
+
export function jsonResultRequested() {
|
|
56
|
+
return resultSlot().json;
|
|
57
|
+
}
|
|
58
|
+
/** Route `process.stdout.write` to stderr; returns the undo. */
|
|
59
|
+
function routeStdoutToStderr() {
|
|
60
|
+
const original = process.stdout.write;
|
|
61
|
+
process.stdout.write = ((chunk, ...rest) => process.stderr.write(chunk, ...rest));
|
|
62
|
+
return () => {
|
|
63
|
+
process.stdout.write = original;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Print the verb's result as one JSON object on stdout: `ok` (the exit code
|
|
68
|
+
* was 0) plus whatever the tool reported. Printed even when the verb refused
|
|
69
|
+
* before reaching a tool (a usage error, emit-only mode), so a `--json` caller
|
|
70
|
+
* always gets one object to parse.
|
|
71
|
+
*/
|
|
72
|
+
export function emitJsonResult() {
|
|
73
|
+
if (!jsonResultRequested())
|
|
74
|
+
return;
|
|
75
|
+
const ok = (process.exitCode ?? 0) === 0;
|
|
76
|
+
process.stdout.write(`${JSON.stringify({ ok, ...resultSlot().fields })}\n`);
|
|
17
77
|
}
|
|
18
78
|
export function addValue(argv, flag, value) {
|
|
19
79
|
if (typeof value === 'string')
|
|
@@ -90,3 +150,40 @@ export function inferCheckMode(family, input, source, compiled) {
|
|
|
90
150
|
}
|
|
91
151
|
return source ? 'source' : compiled ? 'compiled' : inferred;
|
|
92
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* `--compiled` on `<family> check`: hidden from `--help`, still accepted so a
|
|
155
|
+
* script that passes it gets the redirect to `uip maestro <family> validate`.
|
|
156
|
+
*/
|
|
157
|
+
export function retiredCompiledOption() {
|
|
158
|
+
return new Option('--compiled', 'retired: a compiled artifact is checked by `uip maestro <family> validate`').hideHelp();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The primary positional and a named second value (`--original`, `--action`),
|
|
162
|
+
* also accepting the deprecated two-positional form with a warning.
|
|
163
|
+
* `legacyNamedFirst` says where the named value sat in that form: first for
|
|
164
|
+
* merge (`<original> <edited>`), second for prepare (`<key> <action>`). The
|
|
165
|
+
* verb must call `allowExcessArguments()` so the legacy value reaches
|
|
166
|
+
* `command.args`.
|
|
167
|
+
*
|
|
168
|
+
* Returns `[primary, named]`, or `null` after reporting a usage error (exit 2).
|
|
169
|
+
*/
|
|
170
|
+
export function namedOrLegacySecond(command, spec) {
|
|
171
|
+
const [first, extra, ...rest] = command.args;
|
|
172
|
+
const usageError = (message) => {
|
|
173
|
+
refuse(`flow-sdk ${spec.label}: ${message} (usage: ${spec.usage})`);
|
|
174
|
+
return null;
|
|
175
|
+
};
|
|
176
|
+
if (rest.length > 0)
|
|
177
|
+
return usageError(`unexpected argument '${rest[0]}'`);
|
|
178
|
+
if (spec.named !== undefined) {
|
|
179
|
+
if (extra !== undefined)
|
|
180
|
+
return usageError(`pass ${spec.flag} or a second argument, not both`);
|
|
181
|
+
return [first, spec.named];
|
|
182
|
+
}
|
|
183
|
+
if (extra === undefined)
|
|
184
|
+
return usageError(`missing ${spec.flag}`);
|
|
185
|
+
// Spelled for this package's bin: a `uip` release without the named form
|
|
186
|
+
// (before UiPath/cli#4526) rejects it, while `npx flow-sdk …` always works.
|
|
187
|
+
console.error(`flow-sdk ${spec.label}: the two-argument form is deprecated; use \`npx flow-sdk ${spec.usage}\``);
|
|
188
|
+
return spec.legacyNamedFirst ? [extra, first] : [first, extra];
|
|
189
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { Command } from 'commander';
|
|
3
|
+
import { Command, CommanderError } from 'commander';
|
|
4
|
+
import { emitJsonResult, recordJsonError, requestJsonResult } from './common.js';
|
|
4
5
|
import { registerBpmnCommands } from './commands/bpmn.js';
|
|
5
6
|
import { registerCaseCommands } from './commands/case.js';
|
|
6
7
|
import { registerFlowCommands } from './commands/flow.js';
|
|
@@ -15,4 +16,41 @@ registerFlowCommands(program);
|
|
|
15
16
|
registerCaseCommands(program);
|
|
16
17
|
registerBpmnCommands(program);
|
|
17
18
|
registerRegistryCommands(program);
|
|
18
|
-
|
|
19
|
+
// `--json` on every verb (#809): one JSON object on stdout, human lines on
|
|
20
|
+
// stderr. Added here, once, so a new verb cannot ship without it.
|
|
21
|
+
const addJson = (command) => {
|
|
22
|
+
if (command.commands.length > 0) {
|
|
23
|
+
command.commands.forEach(addJson);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (!command.options.some((option) => option.long === '--json')) {
|
|
27
|
+
command.option('--json', 'print the result as one JSON object on stdout (human lines go to stderr)');
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
program.commands.forEach(addJson);
|
|
31
|
+
program.hook('preAction', (_program, action) => {
|
|
32
|
+
if (action.opts().json === true)
|
|
33
|
+
requestJsonResult();
|
|
34
|
+
});
|
|
35
|
+
// A parse error (unknown option, extra argument) is raised before any hook
|
|
36
|
+
// runs, so `--json` is read from argv for that case: the caller still gets its
|
|
37
|
+
// one object. Help and version are the exception — they are text by request.
|
|
38
|
+
program.exitOverride();
|
|
39
|
+
program.commands.forEach(function override(command) {
|
|
40
|
+
command.exitOverride();
|
|
41
|
+
command.commands.forEach(override);
|
|
42
|
+
});
|
|
43
|
+
try {
|
|
44
|
+
await program.parseAsync(process.argv);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!(error instanceof CommanderError))
|
|
48
|
+
throw error;
|
|
49
|
+
process.exitCode = error.exitCode;
|
|
50
|
+
const text = error.code === 'commander.helpDisplayed' || error.code === 'commander.version' || error.code === 'commander.help';
|
|
51
|
+
if (!text && process.argv.includes('--json')) {
|
|
52
|
+
requestJsonResult();
|
|
53
|
+
recordJsonError(error.message);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
emitJsonResult();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-result — the structured result a verb reports for `--json`. One
|
|
3
|
+
* `globalThis` slot because `dist/cli/` and `dist/` are separate builds.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Record fields of this verb's result. Later calls add to earlier ones.
|
|
7
|
+
*
|
|
8
|
+
* Cheap and harmless without `--json`: the fields are kept and never printed.
|
|
9
|
+
*
|
|
10
|
+
* @param fields - JSON-serializable values, e.g. `{ path, nodes, edges }`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function reportResult(fields: Record<string, unknown>): void;
|
|
13
|
+
/**
|
|
14
|
+
* Report a check's diagnostics as `{ errors, warnings, diagnostics }`, the one
|
|
15
|
+
* shape every family's check (and compile's check pass) uses.
|
|
16
|
+
*/
|
|
17
|
+
export declare function reportDiagnostics(diags: ReadonlyArray<{
|
|
18
|
+
level: string;
|
|
19
|
+
code: string;
|
|
20
|
+
message: string;
|
|
21
|
+
suggestion?: string;
|
|
22
|
+
}>): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-result — the structured result a verb reports for `--json`. One
|
|
3
|
+
* `globalThis` slot because `dist/cli/` and `dist/` are separate builds.
|
|
4
|
+
*/
|
|
5
|
+
const SLOT = Symbol.for('uipath.maestro-builder-sdk.cli-result');
|
|
6
|
+
function slot() {
|
|
7
|
+
const global = globalThis;
|
|
8
|
+
global[SLOT] ??= { json: false, fields: {} };
|
|
9
|
+
return global[SLOT];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Record fields of this verb's result. Later calls add to earlier ones.
|
|
13
|
+
*
|
|
14
|
+
* Cheap and harmless without `--json`: the fields are kept and never printed.
|
|
15
|
+
*
|
|
16
|
+
* @param fields - JSON-serializable values, e.g. `{ path, nodes, edges }`.
|
|
17
|
+
*/
|
|
18
|
+
export function reportResult(fields) {
|
|
19
|
+
Object.assign(slot().fields, fields);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Report a check's diagnostics as `{ errors, warnings, diagnostics }`, the one
|
|
23
|
+
* shape every family's check (and compile's check pass) uses.
|
|
24
|
+
*/
|
|
25
|
+
export function reportDiagnostics(diags) {
|
|
26
|
+
reportResult({
|
|
27
|
+
errors: diags.filter((d) => d.level === 'error').length,
|
|
28
|
+
warnings: diags.filter((d) => d.level !== 'error').length,
|
|
29
|
+
diagnostics: diags.map((d) => ({ level: d.level, code: d.code, message: d.message, ...(d.suggestion ? { suggestion: d.suggestion } : {}) })),
|
|
30
|
+
});
|
|
31
|
+
}
|
package/dist/compile-cli.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* product's own gates are supposed to answer. `.build()` still throws on
|
|
18
18
|
* structural problems; only the diagnostic pass is skipped.
|
|
19
19
|
*/
|
|
20
|
+
import { reportDiagnostics, reportResult } from './cli-result.js';
|
|
20
21
|
import { writeFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
21
22
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
22
23
|
import { resolveFlowFile, loadBuiltFlow } from './load.js';
|
|
@@ -123,6 +124,7 @@ export async function run(argv) {
|
|
|
123
124
|
for (const d of diags)
|
|
124
125
|
console.error(` ${d.level === 'error' ? '✗' : '⚠'} [${d.code}] ${d.message}${d.suggestion ? ` (did you mean "${d.suggestion}"?)` : ''}`);
|
|
125
126
|
if (errors.length) {
|
|
127
|
+
reportDiagnostics(diags);
|
|
126
128
|
console.error(`compile: ${errors.length} error(s); not emitting.`);
|
|
127
129
|
return 1;
|
|
128
130
|
}
|
|
@@ -146,6 +148,10 @@ export async function run(argv) {
|
|
|
146
148
|
for (const w of warnings)
|
|
147
149
|
console.error(` ⚠ [${w.code}] ${w.message}`);
|
|
148
150
|
console.error(` ✗ [${error.code}] ${error.message}`);
|
|
151
|
+
reportDiagnostics([
|
|
152
|
+
...warnings.map((w) => ({ level: 'warning', code: w.code, message: w.message })),
|
|
153
|
+
{ level: 'error', code: error.code, message: error.message },
|
|
154
|
+
]);
|
|
149
155
|
console.error('compile: 1 error(s); not emitting.');
|
|
150
156
|
return 1;
|
|
151
157
|
}
|
|
@@ -155,6 +161,10 @@ export async function run(argv) {
|
|
|
155
161
|
const out = opt(argv, '-o') ?? `${built.name || basename(file).replace(/\.flow\.ts$|\.ts$/, '')}.flow`;
|
|
156
162
|
writeFileSync(out, JSON.stringify(flowJson, null, 2) + '\n');
|
|
157
163
|
console.log(`compile: wrote ${out} (${flowJson.nodes.length} nodes, ${flowJson.edges.length} edges)`);
|
|
164
|
+
const written = [];
|
|
165
|
+
reportResult({ path: resolve(out), nodes: flowJson.nodes.length, edges: flowJson.edges.length, sidecars: written });
|
|
166
|
+
// Same keys and types as a failed compile: `warnings` a count, `diagnostics` the list.
|
|
167
|
+
reportDiagnostics(warnings.map((w) => ({ level: 'warning', code: w.code, message: w.message })));
|
|
158
168
|
// An inline agent is TWO artifacts: the node, and the agent's own configuration
|
|
159
169
|
// at `<source>/agent.json` — which is where flow-v1's serializer points the
|
|
160
170
|
// runtime (`entryPoint: "<source>/agent.json"`, resolved relative to the
|
|
@@ -168,11 +178,13 @@ export async function run(argv) {
|
|
|
168
178
|
const target = resolve(outDir, s.path);
|
|
169
179
|
if (target !== outDir && !target.startsWith(outDir + '/')) {
|
|
170
180
|
console.error(`compile: refusing to write a sidecar outside the flow's directory: ${s.path}`);
|
|
181
|
+
reportResult({ error: `refusing to write a sidecar outside the flow's directory: ${s.path}` });
|
|
171
182
|
return 1;
|
|
172
183
|
}
|
|
173
184
|
mkdirSync(dirname(target), { recursive: true });
|
|
174
185
|
writeFileSync(target, JSON.stringify(s.json, null, 2) + '\n');
|
|
175
186
|
console.log(`compile: wrote ${s.path}`);
|
|
187
|
+
written.push(target);
|
|
176
188
|
}
|
|
177
189
|
// PRUNE the agent resources this compile owns but did not write this time.
|
|
178
190
|
// Compile otherwise only ever ADDS files, and an agent resource is keyed by a
|
package/dist/core/actions.d.ts
CHANGED
|
@@ -3153,8 +3153,7 @@ export declare function dynamicExtract(inputs: DynamicExtractInputs): ActionSpec
|
|
|
3153
3153
|
*
|
|
3154
3154
|
* A connector operation's body fields come from the entity, so the library
|
|
3155
3155
|
* cannot carry them: run `uip maestro registry prepare uipath-uipath-dataservice
|
|
3156
|
-
* get-entity-record-by-id -f entityName=<Entity>` first
|
|
3157
|
-
* prepare …` is the same command when invoking the package's own bin directly).
|
|
3156
|
+
* get-entity-record-by-id -f entityName=<Entity>` first.
|
|
3158
3157
|
* The routing table is in the `data-fabric.md` reference and the parent-field
|
|
3159
3158
|
* loop in `connector-params.md` — cited by name rather than linked, because this
|
|
3160
3159
|
* comment renders both into the flat corpus, where those files sit alongside
|
package/dist/core/actions.js
CHANGED
|
@@ -918,8 +918,7 @@ export function dynamicExtract(inputs) {
|
|
|
918
918
|
*
|
|
919
919
|
* A connector operation's body fields come from the entity, so the library
|
|
920
920
|
* cannot carry them: run `uip maestro registry prepare uipath-uipath-dataservice
|
|
921
|
-
* get-entity-record-by-id -f entityName=<Entity>` first
|
|
922
|
-
* prepare …` is the same command when invoking the package's own bin directly).
|
|
921
|
+
* get-entity-record-by-id -f entityName=<Entity>` first.
|
|
923
922
|
* The routing table is in the `data-fabric.md` reference and the parent-field
|
|
924
923
|
* loop in `connector-params.md` — cited by name rather than linked, because this
|
|
925
924
|
* comment renders both into the flat corpus, where those files sit alongside
|
|
@@ -26,17 +26,19 @@ export declare function cliSpelling(env?: CliSpellingEnv): string;
|
|
|
26
26
|
/**
|
|
27
27
|
* A `registry prepare` command line, spelled for whoever is driving.
|
|
28
28
|
*
|
|
29
|
-
* @param
|
|
29
|
+
* @param connectorKey - The connector key, or omitted for the bare command.
|
|
30
|
+
* @param action - The operation, printed as `--action <action>`.
|
|
31
|
+
* @param rest - Further arguments, e.g. `--object`, `<name>`.
|
|
30
32
|
* @returns The full command, no trailing newline.
|
|
31
33
|
*
|
|
32
34
|
* @example
|
|
33
35
|
* ```ts
|
|
34
36
|
* prepareCommand('uipath-salesforce-slack', 'send-message-to-user');
|
|
35
|
-
* // -> "npx flow-sdk registry prepare uipath-salesforce-slack send-message-to-user"
|
|
37
|
+
* // -> "npx flow-sdk registry prepare uipath-salesforce-slack --action send-message-to-user"
|
|
36
38
|
* // -> "uip maestro registry prepare …" when FLOW_SDK_INVOKED_AS="uip maestro"
|
|
37
39
|
* ```
|
|
38
40
|
*/
|
|
39
|
-
export declare function prepareCommand(...
|
|
41
|
+
export declare function prepareCommand(connectorKey?: string, action?: string, ...rest: string[]): string;
|
|
40
42
|
/**
|
|
41
43
|
* The argument of one `--resolve <field>:<by>=<value>`, single-quoted when the
|
|
42
44
|
* shell would otherwise mangle it.
|
|
@@ -47,18 +47,22 @@ export function cliSpelling(env = ambientEnv()) {
|
|
|
47
47
|
/**
|
|
48
48
|
* A `registry prepare` command line, spelled for whoever is driving.
|
|
49
49
|
*
|
|
50
|
-
* @param
|
|
50
|
+
* @param connectorKey - The connector key, or omitted for the bare command.
|
|
51
|
+
* @param action - The operation, printed as `--action <action>`.
|
|
52
|
+
* @param rest - Further arguments, e.g. `--object`, `<name>`.
|
|
51
53
|
* @returns The full command, no trailing newline.
|
|
52
54
|
*
|
|
53
55
|
* @example
|
|
54
56
|
* ```ts
|
|
55
57
|
* prepareCommand('uipath-salesforce-slack', 'send-message-to-user');
|
|
56
|
-
* // -> "npx flow-sdk registry prepare uipath-salesforce-slack send-message-to-user"
|
|
58
|
+
* // -> "npx flow-sdk registry prepare uipath-salesforce-slack --action send-message-to-user"
|
|
57
59
|
* // -> "uip maestro registry prepare …" when FLOW_SDK_INVOKED_AS="uip maestro"
|
|
58
60
|
* ```
|
|
59
61
|
*/
|
|
60
|
-
export function prepareCommand(...
|
|
61
|
-
return [cliSpelling(), 'registry', 'prepare', ...
|
|
62
|
+
export function prepareCommand(connectorKey, action, ...rest) {
|
|
63
|
+
return [cliSpelling(), 'registry', 'prepare', connectorKey, ...(action ? ['--action', action] : []), ...rest]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(' ');
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
64
68
|
* Characters that make a `--resolve` argument unsafe to paste unquoted. `[*]`
|
package/dist/core/lookups.js
CHANGED
|
@@ -285,7 +285,7 @@ export function refuseLookupToken(value, family, field) {
|
|
|
285
285
|
`only Flow reads connectors-local/resolutions.json today, so this would be ` +
|
|
286
286
|
`emitted as a raw token where the connector expects an id.\n` +
|
|
287
287
|
`Resolve it first and pass the value:\n` +
|
|
288
|
-
` ${prepareCommand()} ${nodeType.replace(/^uipath\.connector\.(?:trigger\.|event\.)?/, '').replace(/\.([^.]+)$/, ' $1')} \\\n` +
|
|
288
|
+
` ${prepareCommand()} ${nodeType.replace(/^uipath\.connector\.(?:trigger\.|event\.)?/, '').replace(/\.([^.]+)$/, ' --action $1')} \\\n` +
|
|
289
289
|
` --resolve ${field}:${by}=${String(wanted)}\n` +
|
|
290
290
|
`then read the id out of connectors-local/resolutions.json.`);
|
|
291
291
|
}
|
package/dist/decompile-cli.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* agent can run one script for the whole brownfield write-back loop. Pass
|
|
18
18
|
* `--no-pipeline` to skip it.
|
|
19
19
|
*/
|
|
20
|
+
import { reportResult } from './cli-result.js';
|
|
20
21
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
21
22
|
import { basename, resolve } from 'node:path';
|
|
22
23
|
import { decompile } from './decompile.js';
|
|
@@ -67,10 +68,12 @@ export function run(argv) {
|
|
|
67
68
|
const out = opt(argv, '-o') ?? `${baseName(flow)}.flow.ts`;
|
|
68
69
|
writeFileSync(out, ts);
|
|
69
70
|
console.log(`flow-decompile: wrote ${basename(out)}`);
|
|
71
|
+
reportResult({ path: resolve(out) });
|
|
70
72
|
if (!argv.includes('--no-pipeline')) {
|
|
71
73
|
const pipelinePath = out.replace(/\.flow\.ts$|\.ts$/, '') + '.pipeline.mjs';
|
|
72
74
|
writeFileSync(pipelinePath, pipelineScript(resolve(pos), resolve(out)));
|
|
73
75
|
console.log(`flow-decompile: wrote ${basename(pipelinePath)}`);
|
|
76
|
+
reportResult({ pipeline: resolve(pipelinePath) });
|
|
74
77
|
}
|
|
75
78
|
return 0;
|
|
76
79
|
}
|
package/dist/merge-cli.js
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* omit it for a two-way merge (take the edited graph, re-attach original layout).
|
|
12
12
|
* See merge.ts.
|
|
13
13
|
*/
|
|
14
|
+
import { reportResult } from './cli-result.js';
|
|
14
15
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
15
|
-
import { basename } from 'node:path';
|
|
16
|
+
import { basename, resolve } from 'node:path';
|
|
16
17
|
import { mergeFlow } from './merge.js';
|
|
17
18
|
import { runWhenInvokedDirectly } from './cli-run.js';
|
|
18
19
|
function opt(argv, name) {
|
|
@@ -42,6 +43,7 @@ export function run(argv) {
|
|
|
42
43
|
const out = opt(argv, '-o') ?? 'merged.flow';
|
|
43
44
|
writeFileSync(out, JSON.stringify(merged, null, 2) + '\n');
|
|
44
45
|
console.log(`flow-merge: wrote ${basename(out)} (${(merged.nodes ?? []).length} nodes, ${(merged.edges ?? []).length} edges)`);
|
|
46
|
+
reportResult({ path: resolve(out), nodes: (merged.nodes ?? []).length, edges: (merged.edges ?? []).length });
|
|
45
47
|
return 0;
|
|
46
48
|
}
|
|
47
49
|
runWhenInvokedDirectly(import.meta.url, 'flow-merge', run);
|
|
@@ -24,7 +24,7 @@ export function choosingObjectLines(j, nodeType) {
|
|
|
24
24
|
"casing), then one command matches it deterministically:",
|
|
25
25
|
"",
|
|
26
26
|
"```bash",
|
|
27
|
-
`npx flow-sdk registry prepare ${connectorKey} ${mdAction} --object <name-as-the-task-said-it>`,
|
|
27
|
+
`npx flow-sdk registry prepare ${connectorKey} --action ${mdAction} --object <name-as-the-task-said-it>`,
|
|
28
28
|
"```",
|
|
29
29
|
"",
|
|
30
30
|
"The name is matched, never equality-tested: exact, then " +
|
|
@@ -208,7 +208,7 @@ export function exampleLines(j, fields, symbol, invariant, v1def) {
|
|
|
208
208
|
if (pyTruthy(operation.objectFromDiscovery)) {
|
|
209
209
|
out.push("The descriptor comes from `./connectors-local/` and this " +
|
|
210
210
|
"import resolves only after " +
|
|
211
|
-
`\`npx flow-sdk registry prepare ${connectorKey} ${action} ` +
|
|
211
|
+
`\`npx flow-sdk registry prepare ${connectorKey} --action ${action} ` +
|
|
212
212
|
"--object <name>` runs. That never blocks authoring: write " +
|
|
213
213
|
"the step first with the string form and " +
|
|
214
214
|
"`{ object: '<name-as-the-task-said-it>' }` — `check` " +
|
|
@@ -217,7 +217,7 @@ export function exampleLines(j, fields, symbol, invariant, v1def) {
|
|
|
217
217
|
else {
|
|
218
218
|
out.push("The descriptor comes from `./connectors-local/` and this " +
|
|
219
219
|
"import resolves only after " +
|
|
220
|
-
`\`npx flow-sdk registry prepare ${connectorKey} ${action}\` ` +
|
|
220
|
+
`\`npx flow-sdk registry prepare ${connectorKey} --action ${action}\` ` +
|
|
221
221
|
"runs. That never blocks authoring: the fields in this " +
|
|
222
222
|
"catalog are authorable immediately, and `check` flags any " +
|
|
223
223
|
"input outside them with this same command.");
|
|
@@ -128,7 +128,7 @@ export function lookupLines(connectorKey, action, fields, symbol, invariant) {
|
|
|
128
128
|
out.push("");
|
|
129
129
|
// ONE command carrying every --resolve, and no `--connection-id`.
|
|
130
130
|
out.push("```bash");
|
|
131
|
-
out.push(`npx flow-sdk registry prepare ${connectorKey} ${action} \\`);
|
|
131
|
+
out.push(`npx flow-sdk registry prepare ${connectorKey} --action ${action} \\`);
|
|
132
132
|
// The WIRE name (`users[*]`), which is what prepare's lookup table is keyed
|
|
133
133
|
// on — the authoring name (`users`) is refused as RESOLVE_UNKNOWN_FIELD.
|
|
134
134
|
const resolves = resolvable.map(([f, reference]) => {
|