@uipath/maestro-builder-sdk 6.16.14 → 6.17.1

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 (74) hide show
  1. package/README.md +2 -2
  2. package/dist/api-index.md +115 -114
  3. package/dist/api-members.md +295 -291
  4. package/dist/bindings-v2.d.ts +39 -1
  5. package/dist/bindings-v2.js +289 -9
  6. package/dist/bpmn/compile-cli.js +11 -2
  7. package/dist/bpmn/decompile.js +2 -1
  8. package/dist/bpmn/registry-fallback.js +9 -7
  9. package/dist/case/compile-cli.js +16 -6
  10. package/dist/case/decompile-cli.js +2 -1
  11. package/dist/case/decompile.js +3 -2
  12. package/dist/case/merge-cli.js +3 -2
  13. package/dist/check-cli.js +2 -30
  14. package/dist/check.js +278 -55
  15. package/dist/cli-library.d.ts +18 -4
  16. package/dist/cli-library.js +24 -6
  17. package/dist/cli-result.d.ts +9 -0
  18. package/dist/cli-result.js +12 -0
  19. package/dist/compile-cli.js +82 -86
  20. package/dist/core/actions.d.ts +71 -17
  21. package/dist/core/agentic-process-forms.d.ts +51 -0
  22. package/dist/core/agentic-process-forms.js +49 -0
  23. package/dist/core/binding-messages.d.ts +5 -0
  24. package/dist/core/cli-library.d.ts +16 -7
  25. package/dist/core/cli-library.js +53 -19
  26. package/dist/core/comment-text.d.ts +29 -0
  27. package/dist/core/comment-text.js +40 -0
  28. package/dist/core/connector-checks.d.ts +18 -2
  29. package/dist/core/connector-checks.js +15 -5
  30. package/dist/core/contribution-bindings.d.ts +73 -0
  31. package/dist/core/contribution-bindings.js +105 -0
  32. package/dist/core/error-port.d.ts +25 -0
  33. package/dist/core/error-port.js +36 -0
  34. package/dist/core/expr-check.js +7 -2
  35. package/dist/core/expr.d.ts +11 -5
  36. package/dist/core/expr.js +9 -3
  37. package/dist/core/json-file.d.ts +1 -0
  38. package/dist/core/json-file.js +12 -0
  39. package/dist/core/library.d.ts +19 -0
  40. package/dist/core/library.js +22 -6
  41. package/dist/core/script-return.js +4 -1
  42. package/dist/core/typed-raw-node.js +1 -0
  43. package/dist/core/typescript-module.d.ts +2 -0
  44. package/dist/core/typescript-module.js +18 -0
  45. package/dist/core-definitions.json +210 -0
  46. package/dist/decompile-cli.js +2 -1
  47. package/dist/decompile.js +64 -24
  48. package/dist/emit.js +4 -3
  49. package/dist/flow-sdk.d.ts +18 -12
  50. package/dist/flow-sdk.js +19 -8
  51. package/dist/flow-step-tree.d.ts +2 -3
  52. package/dist/flow-step-tree.js +2 -3
  53. package/dist/load.js +1 -1
  54. package/dist/merge-cli.js +3 -2
  55. package/dist/merge.d.ts +2 -1
  56. package/dist/merge.js +0 -0
  57. package/dist/path-within.d.ts +33 -0
  58. package/dist/path-within.js +41 -0
  59. package/dist/registry/archive/extract.js +2 -5
  60. package/dist/registry/curated-overlay.js +3 -2
  61. package/dist/registry/generators/descriptors.js +20 -18
  62. package/dist/registry/generators/triggers.js +4 -4
  63. package/dist/registry/prepare/messages.js +2 -1
  64. package/dist/registry/prepare/source-labels.js +60 -1
  65. package/dist/registry/prepare-cli.js +14 -4
  66. package/dist/registry/pull-cli.js +3 -2
  67. package/dist/registry/uip/client.d.ts +28 -3
  68. package/dist/registry/uip/client.js +95 -34
  69. package/dist/registry/uip/host.d.ts +41 -0
  70. package/dist/registry/uip/host.js +312 -0
  71. package/dist/serialize.d.ts +7 -0
  72. package/dist/serialize.js +414 -277
  73. package/dist/workdir.js +1 -1
  74. package/package.json +3 -3
@@ -9,10 +9,26 @@
9
9
  import { readFileSync, existsSync } from 'node:fs';
10
10
  import { join } from 'node:path';
11
11
  import { prepareCommand } from './cli-spelling.js';
12
+ import { PULL_COMMAND } from './library-cache.js';
12
13
  import { editDistance } from './edit-distance.js';
13
14
  import { loadListEnvelopes, lookupListEnvelope } from './list-envelope.js';
14
15
  import { lookupSpecOf } from './lookups.js';
15
16
  import { loadByoaLedger, loadInvariantCollections, loadLookupResolutions } from './lookup-store.js';
17
+ /**
18
+ * The refusal {@link Library.resolve} throws, with a `code` for each reason.
19
+ *
20
+ * Typed so a caller can tell a refusal from a bug without matching on message
21
+ * text: `check` reports it under this code with this message, and a compile
22
+ * that throws it carries the same code into its `--json` diagnostics (#948).
23
+ */
24
+ export class ConnectorResolveError extends Error {
25
+ code;
26
+ constructor(code, message) {
27
+ super(message);
28
+ this.name = 'ConnectorResolveError';
29
+ this.code = code;
30
+ }
31
+ }
16
32
  export class Library {
17
33
  layers = [];
18
34
  /** The LIST-ENVELOPE LEDGER, overlay first so a prepared entry can add a row. */
@@ -582,7 +598,7 @@ export class Library {
582
598
  + `the library index (\`index.json\`), and remember the two namespaces: `
583
599
  + `\`…connector.trigger.…\` starts a flow, \`…connector.event.…\` waits mid-flow.`
584
600
  : '';
585
- throw new Error(`connector not in library: ${nodeType}${version ? '@' + version : ''}.${hint}`
601
+ throw new ConnectorResolveError('CONNECTOR_NOT_IN_LIBRARY', `connector not in library: ${nodeType}${version ? '@' + version : ''}.${hint}`
586
602
  + this.describeMiss(nodeType, version, objectName));
587
603
  }
588
604
  /**
@@ -622,7 +638,7 @@ export class Library {
622
638
  + where
623
639
  + ' Note the operation slug is the nodeType segment, NOT the tenant\'s `objectName`'
624
640
  + ' — `uip maestro case spec` reports the latter, and the two can differ.'
625
- + ' If the operation is newer than the library, refresh it with `uip maestro flow registry pull --force`.';
641
+ + ` If the operation is newer than the library, refresh it with \`${PULL_COMMAND}\`.`;
626
642
  }
627
643
  /** Every direct operation id under `prefix` (no further dot), across layers, sorted and de-duplicated. */
628
644
  opsUnder(prefix) {
@@ -646,7 +662,7 @@ export class Library {
646
662
  return ` No connector "${key}" in the library (${keys.length} indexed).`
647
663
  + (near && near !== key ? ` Closest: ${near}.` : '')
648
664
  + where
649
- + ' If the connector is newer than the library, refresh it with `uip maestro flow registry pull --force`.';
665
+ + ` If the connector is newer than the library, refresh it with \`${PULL_COMMAND}\`.`;
650
666
  }
651
667
  /**
652
668
  * The event half of {@link describeMiss}: which of the connector's EVENTS the
@@ -666,7 +682,7 @@ export class Library {
666
682
  const waits = this.opsUnder(`uipath.connector.event.${key}.`);
667
683
  // A start trigger resolves from either form; a mid-flow wait needs the `.event.` form itself.
668
684
  const usable = kind === 'trigger' ? [...new Set([...starts, ...waits])].sort() : waits;
669
- const refresh = ' If the event is newer than the library, refresh it with `uip maestro flow registry pull --force`.';
685
+ const refresh = ` If the event is newer than the library, refresh it with \`${PULL_COMMAND}\`.`;
670
686
  if (usable.length) {
671
687
  if (usable.includes(asked)) {
672
688
  // Only a version can make a carried event miss here: every other refusal
@@ -755,7 +771,7 @@ export class Library {
755
771
  + `dispatch. If it is a typo, compile will not catch it.\n`);
756
772
  return this.build(layer.dir, { ...only, objectName }, nodeType, { objectNameUnverified: true });
757
773
  }
758
- throw new Error(`connector ${nodeType} does not have an object "${objectName}": it is a single, `
774
+ throw new ConnectorResolveError('CONNECTOR_OBJECT_NOT_GENERIC', `connector ${nodeType} does not have an object "${objectName}": it is a single, `
759
775
  + `non-generic operation addressing ${only.objectName ? `"${only.objectName}"` : 'no object'}. `
760
776
  + `Drop the \`object\` option (it is only for generic operations, whose node type covers many objects).`);
761
777
  }
@@ -769,7 +785,7 @@ export class Library {
769
785
  .filter((o) => typeof o === 'string' && o.length > 0)
770
786
  .sort();
771
787
  if (objectName === undefined) {
772
- throw new Error(`connector ${nodeType} is a GENERIC operation covering ${matches.length} objects — `
788
+ throw new ConnectorResolveError('CONNECTOR_OBJECT_REQUIRED', `connector ${nodeType} is a GENERIC operation covering ${matches.length} objects — `
773
789
  + `say which one with the \`object\` option, e.g. `
774
790
  + `connector('${nodeType.split('.').slice(2, 3)[0]}', '${nodeType.split('.').slice(3).join('.')}', `
775
791
  + `{ … }, { object: '${objects[0] ?? '<object>'}' }). ${describeObjects(objects)}`);
@@ -28,7 +28,7 @@
28
28
  * into a designer error — the exact defect this file exists to remove, pointed
29
29
  * the other way.
30
30
  */
31
- import * as ts from 'typescript';
31
+ import { typescript } from './typescript-module.js';
32
32
  /** Normalize whatever the author wrote into the emitted shape. */
33
33
  export function declaredScriptShape(returns) {
34
34
  if (typeof returns === 'string')
@@ -59,6 +59,7 @@ export function declaredScriptShape(returns) {
59
59
  * fields written down says so with `returns: {…}`.
60
60
  */
61
61
  export function inferScriptShape(code) {
62
+ const ts = typescript();
62
63
  // Wrap so a top-level `return` parses — this is how the runtime executes it.
63
64
  const sf = ts.createSourceFile('script.ts', `function __block() {\n${code}\n}`, ts.ScriptTarget.ES2020, true);
64
65
  // `var d = Math.floor(...); return { days: d }` is how these bodies are
@@ -99,6 +100,7 @@ export function inferScriptShape(code) {
99
100
  }
100
101
  /** The type of one expression, or undefined when it is not written down. */
101
102
  function typeOf(expr, locals, depth) {
103
+ const ts = typescript();
102
104
  // Bounded: a local initialized from another local is followed, a cycle is not.
103
105
  if (depth > 8)
104
106
  return undefined;
@@ -163,6 +165,7 @@ function typeOf(expr, locals, depth) {
163
165
  }
164
166
  /** `a + b`, comparisons, and the short-circuit operators. */
165
167
  function binaryShape(e, locals, depth) {
168
+ const ts = typescript();
166
169
  const op = e.operatorToken.kind;
167
170
  // A comparison is a boolean whatever its operands are.
168
171
  if (op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.EqualsEqualsEqualsToken
@@ -55,6 +55,7 @@ export const TYPED_FACTORIES = {
55
55
  'core.logic.switch': { factory: '.switch()', bundled: ['1.0.0', '1.1'] },
56
56
  'core.logic.terminate': { factory: '.terminate()', bundled: ['1.0.0', '1.0'] },
57
57
  'core.subflow': { factory: 'subflow(child, inputs)', bundled: ['1.0.0', '1.0'] },
58
+ 'uipath.agent.autonomous': { factory: 'inlineAgent()', bundled: ['1.2', '1.3', '1.4'] },
58
59
  'uipath.agent.conversational': { factory: 'conversationalAgent()', bundled: ['1.6', '1.7'] },
59
60
  'uipath.agent.voice': { factory: 'voiceAgent()', bundled: ['1.0', '1.1'] },
60
61
  'uipath.conversational.get-conversation-context': { factory: 'conversationContext()', bundled: ['1.0'] },
@@ -0,0 +1,2 @@
1
+ import type * as TS from 'typescript';
2
+ export declare function typescript(): typeof TS;
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * The TypeScript compiler, loaded on first use.
4
+ *
5
+ * Every builder entry reaches the expression and script checkers, and loading the compiler
6
+ * costs ~120 ms that a flow which never runs those checks should not pay (FB009). The
7
+ * specifier stays a literal at the call so the architecture lint sees the edge (as a lazy
8
+ * one); FB005 keeps this the only definition.
9
+ *
10
+ * The triple-slash reference: tests type-check generated code against `flow-sdk.ts`'s
11
+ * import graph without `@types/node` in scope, and this is the one `node:` import in that
12
+ * graph. Without it they fail with TS2307 on 'node:module'. It is not emitted into the .d.ts.
13
+ */
14
+ import { createRequire } from 'node:module';
15
+ let typescriptModule;
16
+ export function typescript() {
17
+ return (typescriptModule ??= createRequire(import.meta.url)('typescript'));
18
+ }
@@ -8852,6 +8852,216 @@
8852
8852
  ]
8853
8853
  }
8854
8854
  },
8855
+ "uipath.agent.autonomous@1.2": {
8856
+ "nodeType": "uipath.agent.autonomous",
8857
+ "version": "1.2",
8858
+ "category": "agent",
8859
+ "description": "AI agent that completes tasks autonomously",
8860
+ "tags": [
8861
+ "agentic",
8862
+ "ai",
8863
+ "autonomous",
8864
+ "agent"
8865
+ ],
8866
+ "sortOrder": 5,
8867
+ "supportsErrorHandling": true,
8868
+ "display": {
8869
+ "label": "Autonomous Agent",
8870
+ "icon": "autonomous-agent",
8871
+ "shape": "rectangle"
8872
+ },
8873
+ "handleConfiguration": [
8874
+ {
8875
+ "position": "top",
8876
+ "handles": [
8877
+ {
8878
+ "id": "escalation",
8879
+ "type": "source",
8880
+ "handleType": "artifact",
8881
+ "label": "Escalations",
8882
+ "showButton": true,
8883
+ "constraints": {
8884
+ "allowedTargets": [
8885
+ {
8886
+ "nodeType": "uipath.agent.resource.escalation"
8887
+ },
8888
+ {
8889
+ "nodeType": "uipath.agent.resource.escalation.*"
8890
+ }
8891
+ ],
8892
+ "validationMessage": "Only Agent Escalation nodes can connect here"
8893
+ }
8894
+ }
8895
+ ]
8896
+ },
8897
+ {
8898
+ "position": "bottom",
8899
+ "handles": [
8900
+ {
8901
+ "id": "context",
8902
+ "type": "source",
8903
+ "handleType": "artifact",
8904
+ "label": "Context",
8905
+ "showButton": true,
8906
+ "constraints": {
8907
+ "allowedTargets": [
8908
+ {
8909
+ "nodeType": "uipath.agent.resource.context.*"
8910
+ }
8911
+ ],
8912
+ "validationMessage": "Only Context resource nodes can connect here"
8913
+ }
8914
+ },
8915
+ {
8916
+ "id": "tool",
8917
+ "type": "source",
8918
+ "handleType": "artifact",
8919
+ "label": "Tools",
8920
+ "showButton": true,
8921
+ "constraints": {
8922
+ "allowedTargets": [
8923
+ {
8924
+ "nodeType": "uipath.agent.resource.tool.*"
8925
+ }
8926
+ ],
8927
+ "validationMessage": "Only Tool resource nodes can connect here"
8928
+ }
8929
+ }
8930
+ ]
8931
+ },
8932
+ {
8933
+ "position": "left",
8934
+ "handles": [
8935
+ {
8936
+ "id": "input",
8937
+ "type": "target",
8938
+ "handleType": "input"
8939
+ }
8940
+ ]
8941
+ },
8942
+ {
8943
+ "position": "right",
8944
+ "handles": [
8945
+ {
8946
+ "id": "success",
8947
+ "type": "source",
8948
+ "handleType": "output",
8949
+ "isDefaultForType": true
8950
+ },
8951
+ {
8952
+ "id": "error",
8953
+ "type": "source",
8954
+ "handleType": "output",
8955
+ "label": "Error",
8956
+ "visible": "{inputs.errorHandlingEnabled}",
8957
+ "constraints": {
8958
+ "maxConnections": 1
8959
+ }
8960
+ }
8961
+ ]
8962
+ }
8963
+ ],
8964
+ "inputDefinition": {
8965
+ "type": "object",
8966
+ "properties": {
8967
+ "systemPrompt": {
8968
+ "type": "string",
8969
+ "minLength": 1,
8970
+ "errorMessage": {
8971
+ "minLength": "System prompt is required"
8972
+ }
8973
+ },
8974
+ "userPrompt": {
8975
+ "type": "string",
8976
+ "minLength": 1,
8977
+ "errorMessage": {
8978
+ "minLength": "User prompt is required"
8979
+ }
8980
+ },
8981
+ "model": {
8982
+ "type": "string",
8983
+ "minLength": 1,
8984
+ "errorMessage": {
8985
+ "minLength": "Model is required"
8986
+ }
8987
+ },
8988
+ "temperature": {
8989
+ "type": "number",
8990
+ "minimum": 0,
8991
+ "maximum": 1
8992
+ },
8993
+ "maxTokenPerResponse": {
8994
+ "type": "number",
8995
+ "minimum": 0,
8996
+ "maximum": 16384
8997
+ },
8998
+ "modelMaxTokens": {
8999
+ "type": "number",
9000
+ "minimum": 0
9001
+ },
9002
+ "maxIterations": {
9003
+ "type": "number",
9004
+ "minimum": 1,
9005
+ "maximum": 100
9006
+ },
9007
+ "guardrails": {
9008
+ "type": "array"
9009
+ },
9010
+ "agentInputVariables": {
9011
+ "type": "array"
9012
+ },
9013
+ "agentOutputVariables": {
9014
+ "type": "array"
9015
+ }
9016
+ },
9017
+ "required": [
9018
+ "systemPrompt",
9019
+ "userPrompt",
9020
+ "model"
9021
+ ]
9022
+ },
9023
+ "inputDefaults": {},
9024
+ "outputDefinition": {
9025
+ "output": {
9026
+ "type": "object",
9027
+ "description": "Agent response",
9028
+ "source": "=result.response",
9029
+ "var": "output"
9030
+ },
9031
+ "error": {
9032
+ "type": "object",
9033
+ "description": "Error information if the node fails",
9034
+ "source": "=Error",
9035
+ "var": "error"
9036
+ }
9037
+ },
9038
+ "model": {
9039
+ "source": true,
9040
+ "type": "bpmn:ServiceTask",
9041
+ "serviceType": "Orchestrator.StartInlineAgentJob",
9042
+ "version": "v2",
9043
+ "context": [
9044
+ {
9045
+ "name": "_label",
9046
+ "type": "string",
9047
+ "value": ""
9048
+ },
9049
+ {
9050
+ "name": "name",
9051
+ "type": "string",
9052
+ "value": ""
9053
+ },
9054
+ {
9055
+ "name": "entryPoint",
9056
+ "type": "string",
9057
+ "value": ""
9058
+ }
9059
+ ]
9060
+ },
9061
+ "debug": {
9062
+ "runtime": "bpmnEngine"
9063
+ }
9064
+ },
8855
9065
  "uipath.agent.autonomous@1.3": {
8856
9066
  "nodeType": "uipath.agent.autonomous",
8857
9067
  "version": "1.3",
@@ -25,6 +25,7 @@ import { decompile } from './decompile.js';
25
25
  import { resolveFlowRefs } from './ref-resolve.js';
26
26
  import { flagValue, runWhenInvokedDirectly } from './cli-run.js';
27
27
  import { PACKAGE_NAME } from './package-name.js';
28
+ import { commentText } from './core/comment-text.js';
28
29
  /** Derive a PascalCase base name from the flow name/id for the default output file. */
29
30
  function baseName(flow) {
30
31
  const src = flow.name ?? flow.id ?? 'Flow';
@@ -101,7 +102,7 @@ function pipelineScript(originalPath, tsPath, pipelinePath) {
101
102
  const base = pipelinePath.replace(/\.pipeline\.mjs$/, '');
102
103
  return `#!/usr/bin/env node
103
104
  // Generated by flow-decompile — the brownfield read/modify/write pipeline for
104
- // ${basename(originalPath)}. Run it, edit ${basename(tsPath)}, run it again.
105
+ // ${commentText(basename(originalPath))}. Run it, edit ${commentText(basename(tsPath))}, run it again.
105
106
  import { execFileSync, spawnSync } from 'node:child_process';
106
107
  import { existsSync } from 'node:fs';
107
108
 
package/dist/decompile.js CHANGED
@@ -35,6 +35,7 @@ import { dirname, join } from 'node:path';
35
35
  import { fileURLToPath } from 'node:url';
36
36
  import { inferScriptShape } from './core/script-return.js';
37
37
  import { DEFAULT_TRIGGER_ID } from './core/expr.js';
38
+ import { commentText } from './core/comment-text.js';
38
39
  import { parseIxpProjectType } from './core/actions.js';
39
40
  import { readFlowGlobals } from './flow-variables.js';
40
41
  import { missingBindingLabels } from './core/binding-messages.js';
@@ -95,7 +96,19 @@ function warnOnce(message) {
95
96
  * emitted source; saying so here is the difference between a loop that fails
96
97
  * at step 2 with a hint and one that fails at step 2 with a puzzle.
97
98
  */
98
- const CORE_DEFINITION_KEYS = new Set(Object.keys(JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8'))));
99
+ const CORE_DEFINITIONS = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8'));
100
+ const CORE_DEFINITION_KEYS = new Set(Object.keys(CORE_DEFINITIONS));
101
+ /**
102
+ * The label the canvas gives a freshly dropped `node`: its definition's
103
+ * `display.label`, from the file's own `definitions[]`, else the bundled core
104
+ * definition. `serialize` uses the same label when the author sets none.
105
+ */
106
+ function definitionLabel(node) {
107
+ const key = `${node.type}@${node.typeVersion}`;
108
+ const def = runDefs.get(key) ?? CORE_DEFINITIONS[key] ?? runDefs.get(node.type);
109
+ const label = def?.display?.label;
110
+ return typeof label === 'string' ? label : undefined;
111
+ }
99
112
  function verClause(node) {
100
113
  const tv = node.typeVersion;
101
114
  if (!tv) {
@@ -124,6 +137,25 @@ function verArg(node) {
124
137
  const clause = verClause(node);
125
138
  return clause ? `, { ${clause} }` : '';
126
139
  }
140
+ /**
141
+ * A trigger node's option clauses: its exact `version`, and its canvas `label`
142
+ * when that differs from the definition's label (`definitionLabel`).
143
+ */
144
+ function triggerOptParts(node) {
145
+ const parts = [];
146
+ const ver = verClause(node);
147
+ if (ver)
148
+ parts.push(ver);
149
+ const label = node.display?.label;
150
+ if (typeof label === 'string' && label !== definitionLabel(node))
151
+ parts.push(`label: ${str(label)}`);
152
+ return parts;
153
+ }
154
+ /** `triggerOptParts` as the `.trigger(spec, { ... })` options argument. */
155
+ function triggerOptsArg(node) {
156
+ const parts = triggerOptParts(node);
157
+ return parts.length ? `, { ${parts.join(', ')} }` : '';
158
+ }
127
159
  /**
128
160
  * The full node-options argument for steps that can carry both an exact
129
161
  * `version` and mid-flow `updates` (the format's `variableUpdates[nodeId]`,
@@ -1083,11 +1115,12 @@ function sidecarAgentInputs(node) {
1083
1115
  ? numberUnless(settings.maxIterations, STUDIO_WEB_DEFAULT_MAX_ITERATIONS)
1084
1116
  : typeof settings.maxIterations === 'number' ? settings.maxIterations : undefined;
1085
1117
  // `mode` is a harness choice on the inline agent only; the conversational and
1086
- // voice sidecars always carry their family's fixed value. Naming it is also
1087
- // what selects the 1.3 definition, so on a 1.3 node even `'standard'` was the
1088
- // author's.
1118
+ // voice sidecars always carry their family's fixed value. `'standard'` is the
1119
+ // sidecar's default, so only another value is the author's. (Naming it no
1120
+ // longer selects a definition version — the node's `{ version }` carries that,
1121
+ // flow-builder-sdk#956.)
1089
1122
  const mode = node.type === T.inlineAgent && typeof settings.mode === 'string'
1090
- && (settings.mode !== 'standard' || node.typeVersion === '1.3')
1123
+ && settings.mode !== 'standard'
1091
1124
  ? settings.mode : undefined;
1092
1125
  return {
1093
1126
  ...(system === undefined ? {} : { systemPrompt: system }),
@@ -1616,7 +1649,7 @@ function unboundMarker(node, labels, key, action) {
1616
1649
  + `The source leaves ${missing.length > 1 ? 'them' : 'it'} out, and compile refuses the node (BINDING_MISSING) `
1617
1650
  + `until it names both labels: run \`${prepareCommand(key, action ?? '<action>')}\`, then pass `
1618
1651
  + `\`connection\` and \`folder\`.`);
1619
- return ` /* TODO: bind ${names}; compile refuses this node until it has both labels (BINDING_MISSING) */`;
1652
+ return ` /* TODO: bind ${commentText(names)}; compile refuses this node until it has both labels (BINDING_MISSING) */`;
1620
1653
  }
1621
1654
  function emitEventSubscription(node, imp, inputNames) {
1622
1655
  const prefix = node.type.startsWith('uipath.connector.event.') ? 'uipath.connector.event.'
@@ -1705,6 +1738,13 @@ function emitPublishedResource(node, imp, inputNames) {
1705
1738
  // definition to read there is nothing to recover it from.
1706
1739
  const name = binding('name');
1707
1740
  const folderPath = binding('folderPath');
1741
+ // A sibling project of the same solution (#951): the model names its project
1742
+ // instead of a folder. `isInSolution` is flow-core's marker; an in-solution
1743
+ // agent emitted before #951 carries only `projectId`. Read back as
1744
+ // `location: 'in-solution'` so the recompile takes the in-solution path
1745
+ // instead of a published one with an empty folder.
1746
+ const projectId = typeof def?.model?.projectId === 'string' ? def.model.projectId : undefined;
1747
+ const inSolution = def?.model?.isInSolution === true || projectId !== undefined;
1708
1748
  const inputs = { ...(node.inputs ?? {}) };
1709
1749
  // The design-time fire-and-forget switch is an OPTION on the factory, not a
1710
1750
  // process argument — serialize adds it to `inputs` after rendering the
@@ -1720,7 +1760,9 @@ function emitPublishedResource(node, imp, inputNames) {
1720
1760
  return `${imp.use(family.factory)}(${opts([
1721
1761
  ['key', str(key)],
1722
1762
  ['name', name !== undefined ? str(name) : undefined],
1723
- ['folderPath', folderPath !== undefined ? str(folderPath) : undefined],
1763
+ ['location', inSolution ? str('in-solution') : undefined],
1764
+ ['folderPath', !inSolution && folderPath !== undefined ? str(folderPath) : undefined],
1765
+ ['projectId', inSolution && projectId !== undefined ? str(projectId) : undefined],
1724
1766
  ['inputs', inputRows.length ? objLit(inputRows) : undefined],
1725
1767
  ['returns', returns],
1726
1768
  ['form', family.form !== undefined ? str(family.form) : undefined],
@@ -1792,7 +1834,7 @@ function unsupportedSpec(node, imp, o) {
1792
1834
  }
1793
1835
  // No definition to carry: a mock publishes nothing and takes no inputs, so it
1794
1836
  // is a safe structural stand-in, and the marker records what it replaced.
1795
- return `${imp.use('mock')}() /* TODO: unsupported node type ${node.type} */`;
1837
+ return `${imp.use('mock')}() /* TODO: unsupported node type ${commentText(node.type)} */`;
1796
1838
  }
1797
1839
  /** `some-node.id` → `someNodeId`, for a hoisted const name. */
1798
1840
  function camel(id) {
@@ -1902,39 +1944,39 @@ function emitTrigger(e, depth, trigger, imp, o, inputNames = new Set()) {
1902
1944
  // The default trigger, spelled out: decompiled source is deliberately more
1903
1945
  // explicit than hand-authored source so the node's exact definition version
1904
1946
  // survives recompilation (design §5.3).
1905
- e.line(depth, `.trigger(${imp.use('manual')}()${verArg(trigger)})`);
1947
+ e.line(depth, `.trigger(${imp.use('manual')}()${triggerOptsArg(trigger)})`);
1906
1948
  return;
1907
1949
  }
1908
1950
  if (trigger.type === T.triggerScheduled) {
1909
- e.line(depth, `.trigger(${imp.use('scheduled')}(${opts([['every', str(scheduleEvery(trigger))]])})${verArg(trigger)})`);
1951
+ e.line(depth, `.trigger(${imp.use('scheduled')}(${opts([['every', str(scheduleEvery(trigger))]])})${triggerOptsArg(trigger)})`);
1910
1952
  return;
1911
1953
  }
1912
1954
  if (trigger.type === T.triggerForm) {
1913
1955
  // The schema is DERIVED from the flow's inputs at compile time, so nothing
1914
1956
  // of it needs recovering — the factory takes no arguments.
1915
- e.line(depth, `.trigger(${imp.use('formTrigger')}()${verArg(trigger)})`);
1957
+ e.line(depth, `.trigger(${imp.use('formTrigger')}()${triggerOptsArg(trigger)})`);
1916
1958
  return;
1917
1959
  }
1918
1960
  if (trigger.type === T.triggerConversation) {
1919
- e.line(depth, `.trigger(${imp.use('conversationTrigger')}()${verArg(trigger)})`);
1961
+ e.line(depth, `.trigger(${imp.use('conversationTrigger')}()${triggerOptsArg(trigger)})`);
1920
1962
  return;
1921
1963
  }
1922
1964
  if (trigger.type === T.triggerVoice) {
1923
- e.line(depth, `.trigger(${imp.use('voiceTrigger')}()${verArg(trigger)})`);
1965
+ e.line(depth, `.trigger(${imp.use('voiceTrigger')}()${triggerOptsArg(trigger)})`);
1924
1966
  return;
1925
1967
  }
1926
1968
  // A connector EVENT trigger — the same subscription body as a mid-flow wait.
1927
1969
  {
1928
1970
  const sub = emitEventSubscription(trigger, imp, inputNames);
1929
1971
  if (sub !== undefined) {
1930
- e.line(depth, `.trigger(${imp.use('onEvent')}(${sub})${verArg(trigger)})`);
1972
+ e.line(depth, `.trigger(${imp.use('onEvent')}(${sub})${triggerOptsArg(trigger)})`);
1931
1973
  return;
1932
1974
  }
1933
1975
  }
1934
1976
  if (o.bestEffort === false) {
1935
1977
  throw new Error(`decompile: unsupported trigger type "${trigger.type}".`);
1936
1978
  }
1937
- e.line(depth, `/* TODO: unsupported trigger type ${trigger.type} */`);
1979
+ e.line(depth, `/* TODO: unsupported trigger type ${commentText(trigger.type)} */`);
1938
1980
  }
1939
1981
  // ─── Control-flow reconstruction (Phase 3) ────────────────────────────────────
1940
1982
  //
@@ -2350,7 +2392,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
2350
2392
  // Unstructured fan-out we can't fold — best-effort marker.
2351
2393
  if (ctx.o.bestEffort === false)
2352
2394
  throw new Error(`decompile: unstructured fan-out at "${node.id}".`);
2353
- segs.push(`/* TODO: unstructured fan-out at ${node.id} (${succ.length} successors) */`);
2395
+ segs.push(`/* TODO: unstructured fan-out at ${commentText(node.id)} (${commentText(succ.length)} successors) */`);
2354
2396
  return segs;
2355
2397
  }
2356
2398
  return segs;
@@ -2637,7 +2679,7 @@ function emitSubflow(node, ctx) {
2637
2679
  if (!child) {
2638
2680
  if (ctx.o.bestEffort === false)
2639
2681
  throw new Error(`decompile: subflow "${node.id}" has no body in subflows[].`);
2640
- return `${ctx.imp.use('mock')}() /* TODO: subflow ${node.id} body missing */`;
2682
+ return `${ctx.imp.use('mock')}() /* TODO: subflow ${commentText(node.id)} body missing */`;
2641
2683
  }
2642
2684
  const childName = `${node.id}Child`;
2643
2685
  const childSrc = emitChildFlow(childName, child, ctx);
@@ -2736,7 +2778,7 @@ export function decompile(flow, options = {}) {
2736
2778
  if (runStrict)
2737
2779
  throw new Error(`decompile: ${schema.problem}`);
2738
2780
  warnOnce(schema.problem);
2739
- e.line(d, `// TODO: ${schema.problem}`);
2781
+ e.line(d, `// TODO: ${commentText(schema.problem)}`);
2740
2782
  }
2741
2783
  if (flow.name !== undefined && flow.name !== flow.id)
2742
2784
  e.line(d, `.name(${str(flow.name)})`);
@@ -2772,7 +2814,7 @@ export function decompile(flow, options = {}) {
2772
2814
  throw new Error(`decompile: ${message}`);
2773
2815
  warnOnce(message);
2774
2816
  for (const n of detached) {
2775
- e.line(d, `// TODO: node ${str(n.id)} (${n.type}) is not reachable from any trigger and is NOT in this source; recompiling drops it. Connect it in the .flow or edit its JSON directly.`);
2817
+ e.line(d, `// TODO: node ${commentText(str(n.id))} (${commentText(n.type)}) is not reachable from any trigger and is NOT in this source; recompiling drops it. Connect it in the .flow or edit its JSON directly.`);
2776
2818
  }
2777
2819
  }
2778
2820
  // `{ shared }` input copies on the roots (#924). Any other trigger-level
@@ -2786,7 +2828,7 @@ export function decompile(flow, options = {}) {
2786
2828
  if (runStrict)
2787
2829
  throw new Error(`decompile: ${message}`);
2788
2830
  warnOnce(message);
2789
- e.line(d, `// TODO: ${message}`);
2831
+ e.line(d, `// TODO: ${commentText(message)}`);
2790
2832
  }
2791
2833
  emitVariables(e, d, flow, imp, new Set(triggerNodes.filter((t) => t !== trigger).map((t) => t.id)), shared);
2792
2834
  // Reconstruct the body: structured control flow recovered from the graph.
@@ -2876,7 +2918,7 @@ function entryPointSeg(t, scope, ipdom, ctx) {
2876
2918
  : (() => {
2877
2919
  if (ctx.o.bestEffort === false)
2878
2920
  throw new Error(`decompile: unsupported entry-point trigger type "${t.type}".`);
2879
- return `${ctx.imp.use('manual')}() /* TODO: unsupported trigger type ${t.type} */`;
2921
+ return `${ctx.imp.use('manual')}() /* TODO: unsupported trigger type ${commentText(t.type)} */`;
2880
2922
  })();
2881
2923
  const scoped = readFlowGlobals(ctx.flow.variables, runStrict)
2882
2924
  .filter((g) => g.direction === 'in' && g.triggerNodeId === t.id);
@@ -2885,9 +2927,7 @@ function entryPointSeg(t, scope, ipdom, ctx) {
2885
2927
  const sharedOf = (g) => ctx.shared?.byInput.get(`${t.id}\0${g.id}`);
2886
2928
  optParts.push(`inputs: { ${scoped.map((g) => `${key(g.name ?? g.id)}: ${declExpr(g, true, ctx.imp, sharedOf(g))}`).join(', ')} }`);
2887
2929
  }
2888
- const ver = verClause(t);
2889
- if (ver)
2890
- optParts.push(ver);
2930
+ optParts.push(...triggerOptParts(t));
2891
2931
  const first = scopeSucc(ctx.graph, t.id, scope)[0];
2892
2932
  const prefixSegs = first !== undefined ? region(first, EXIT, scope, ipdom, ctx) : [];
2893
2933
  const optArgText = optParts.length ? `, { ${optParts.join(', ')} }` : (prefixSegs.length ? ', undefined' : '');
package/dist/emit.js CHANGED
@@ -25,13 +25,14 @@
25
25
  * are the ones `.build()` and `serialize()` raise themselves. Callers who want
26
26
  * the static pass should call `check()` — or use `compile-cli`.
27
27
  */
28
- import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
28
+ import { existsSync, mkdirSync } from 'node:fs';
29
29
  import { dirname, join } from 'node:path';
30
30
  import { serialize } from './serialize.js';
31
31
  import { Library } from './library.js';
32
32
  import { Bindings } from './bindings.js';
33
33
  import { resolveLibraryDir } from './core/library-cache.js';
34
34
  import { defaultBindingsFile } from './workdir.js';
35
+ import { writeJsonFile } from './core/json-file.js';
35
36
  /**
36
37
  * Resolve the connector library the same way `compile-cli` does: only load it
37
38
  * when it is actually there, so a flow with no connectors emits fine without a
@@ -51,11 +52,11 @@ export function emitFlow(built, path, opts = {}) {
51
52
  library: opts.library ?? defaultLibrary(opts.libraryDir),
52
53
  bindings: opts.bindings ?? new Bindings(bindFile),
53
54
  // Same channel `compile` uses; a host that wants them elsewhere passes `warn`.
54
- warn: opts.warn ?? ((w) => console.error(` ⚠ [${w.code}] ${w.message}`)),
55
+ warn: opts.warn ?? ((w) => process.stderr.write(` ⚠ [${w.code}] ${w.message}\n`)),
55
56
  });
56
57
  const dir = dirname(path);
57
58
  if (dir && dir !== '.' && !existsSync(dir))
58
59
  mkdirSync(dir, { recursive: true });
59
- writeFileSync(path, JSON.stringify(flowJson, null, 2) + '\n');
60
+ writeJsonFile(path, flowJson);
60
61
  return flowJson;
61
62
  }