@uipath/maestro-builder-sdk 6.24.0 → 6.25.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.
package/dist/decompile.js CHANGED
@@ -45,7 +45,7 @@ import { outputBackingGlobal, outputBackingName } from './flow-output-backing.js
45
45
  import { mapJsCode } from './core/js-code-spans.js';
46
46
  import { missingBindingLabels } from './core/binding-messages.js';
47
47
  import { prepareCommand } from './core/cli-spelling.js';
48
- import { OUTCOME_HANDLE_NODE_TYPES, outcomeSlug } from './core/hitl-routing.js';
48
+ import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
49
49
  import { STICKY_NOTE_TYPE } from './core/definitionless-node-types.js';
50
50
  import { eventFilterFromTreeLeaf } from './core/event-filters.js';
51
51
  import { sdkFormFieldType } from './core/form-field-type.js';
@@ -226,9 +226,6 @@ const T = {
226
226
  inlineAgent: 'uipath.agent.autonomous',
227
227
  conversationalAgent: 'uipath.agent.conversational',
228
228
  voiceAgent: 'uipath.agent.voice',
229
- hitlQuickForm: 'uipath.human-in-the-loop.quick-form',
230
- hitlActionApp: 'uipath.human-in-the-loop.coded-action-app',
231
- hitlDocValidation: 'uipath.human-in-the-loop.document-validation',
232
229
  triggerVoice: 'core.trigger.voice',
233
230
  createOutgoingCall: 'uipath.conversational.voice.create-outgoing-call',
234
231
  endCall: 'uipath.conversational.voice.end-call',
@@ -560,7 +557,7 @@ function registeredImpl(node) {
560
557
  * the node. A node at a version the type does not register is lifted by its
561
558
  * default version's implementation, as every built-in family lifts any version.
562
559
  */
563
- function liftRegistered(node, impl = registeredImpl(node)) {
560
+ function liftRegistered(node, impl = registeredImpl(node), graph) {
564
561
  if (!impl)
565
562
  return undefined;
566
563
  const version = String(node.typeVersion ?? '');
@@ -574,6 +571,8 @@ function liftRegistered(node, impl = registeredImpl(node)) {
574
571
  // when the file carries none (a hand-trimmed or SDK-written file).
575
572
  definition: () => runDefs.get(`${node.type}@${version}`) ?? BUNDLED_DEFINITIONS[`${node.type}@${version}`] ?? runDefs.get(node.type),
576
573
  warn: warnOnce,
574
+ outPorts: () => (graph?.outEdges(node.id) ?? []).map((e) => e.sourcePort),
575
+ convergedFanOut: () => graph?.convergedFanOut(node.id) === true,
577
576
  };
578
577
  const spec = impl.deserialize(node, ctx);
579
578
  return spec === undefined ? undefined : { impl, spec };
@@ -586,8 +585,8 @@ function liftRegistered(node, impl = registeredImpl(node)) {
586
585
  * `{ version }` the type does not register, with a warning. `undefined` when the type is not registered, or the node type declines
587
586
  * the node; the caller's branches take it from there.
588
587
  */
589
- function emitRegisteredSpec(node, imp, inputNames) {
590
- const lifted = liftRegistered(node);
588
+ function emitRegisteredSpec(node, imp, inputNames, graph) {
589
+ const lifted = liftRegistered(node, registeredImpl(node), graph);
591
590
  if (!lifted)
592
591
  return undefined;
593
592
  const { impl, spec } = lifted;
@@ -629,7 +628,7 @@ function emitRegisteredSpec(node, imp, inputNames) {
629
628
  function emitStepSpec(node, imp, inputNames, o, graph) {
630
629
  // A registered node type lifts itself; every other type falls through to the
631
630
  // branches below until its family is ported (FB014's pins are the list).
632
- const lifted = emitRegisteredSpec(node, imp, inputNames);
631
+ const lifted = emitRegisteredSpec(node, imp, inputNames, graph);
633
632
  if (lifted !== undefined)
634
633
  return lifted;
635
634
  switch (node.type) {
@@ -651,11 +650,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
651
650
  case T.conversationalAgent:
652
651
  case T.voiceAgent:
653
652
  return emitAgentCluster(node, imp, inputNames, graph);
654
- case T.hitl:
655
- case T.hitlQuickForm:
656
- case T.hitlActionApp:
657
- case T.hitlDocValidation:
658
- return emitHitl(node, imp, inputNames, graph);
659
653
  default:
660
654
  // A connector action node: `uipath.connector.<key>.<action>` (but NOT the
661
655
  // event nodes `uipath.connector.event.*` / `.trigger.*`, which are triggers).
@@ -1260,184 +1254,6 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1260
1254
  ['source', tsLiteral(plain(i.source) ?? '')],
1261
1255
  ])})`;
1262
1256
  }
1263
- /**
1264
- * A HUMAN TASK — the base node plus its three sub-typed variants.
1265
- *
1266
- * `hitlInputs` is the widest lowering in the serializer, so this inverts it
1267
- * field by field. Three of its outputs are DERIVED and deliberately not
1268
- * recovered: `schema.schemaId` (a stable hash of the flow and node ids),
1269
- * `type: 'quick'` (the base node's discriminator), and the `variable`/`binding`
1270
- * wiring each field row carries — all of them are re-emitted from what comes
1271
- * back here.
1272
- *
1273
- * A value equal to what serialize would have DEFAULTED is omitted rather than
1274
- * recovered: the step's own name for `title`, `'Low'` for `priority`, and the
1275
- * definition's own `inputDefaults.recipient` for delivery. Recovering those
1276
- * would add arguments the author never wrote to every task.
1277
- */
1278
- function emitHitl(node, imp, inputNames, graph) {
1279
- const i = (node.inputs ?? {});
1280
- const schema = (i.schema ?? {});
1281
- const plain = (v) => {
1282
- const raw = unwrapSource(v);
1283
- return raw === undefined || raw === '' ? undefined : raw;
1284
- };
1285
- const variant = node.type === T.hitlQuickForm ? 'quick-form'
1286
- : node.type === T.hitlActionApp ? 'action-app'
1287
- : node.type === T.hitlDocValidation ? 'document-validation'
1288
- : undefined;
1289
- // A field row's binding is a variable PATH (`vars.x`), not an expression —
1290
- // serialize rewrote the author's `$vars.x` on the way out, so put it back.
1291
- const bindingExpr = (v) => {
1292
- const raw = plain(v);
1293
- if (raw === undefined)
1294
- return undefined;
1295
- const js = wireExprBody(raw);
1296
- return emitBareExpr(js.startsWith('vars.') ? `$${js}` : js, imp, inputNames);
1297
- };
1298
- const rows = (Array.isArray(schema.fields) ? schema.fields : []);
1299
- const fields = rows.map((f) => {
1300
- const id = String(f.id ?? '');
1301
- const direction = String(f.direction ?? 'output');
1302
- return opts([
1303
- ['id', tsLiteral(id)],
1304
- // serialize defaults a row's label to its id.
1305
- ['label', typeof f.label === 'string' && f.label !== id ? tsLiteral(f.label) : undefined],
1306
- // The product's own spelling (`"string"`, `"datetime"`, …) → the SDK's (#1143).
1307
- ['type', tsLiteral(sdkFormFieldType(f.type ?? 'text') ?? String(f.type))],
1308
- ['direction', tsLiteral(direction)],
1309
- ['value', direction === 'input' || direction === 'inOut' ? bindingExpr(f.binding) : undefined],
1310
- ['required', f.required === true ? 'true' : undefined],
1311
- ]);
1312
- });
1313
- const outcomeRows = (Array.isArray(schema.outcomes) ? schema.outcomes : []);
1314
- const outcomes = outcomeRows.map((o, idx) => {
1315
- const name = String(o.name ?? '');
1316
- // The file's id comes back only when serialize would not derive it from the
1317
- // name: a designer-drawn task's ids (`outcome-1778015958049`) are not slugs,
1318
- // and merge keeps the ORIGINAL node, so recompiled edges must use its ids
1319
- // (#1130). An SDK-written task's ids are slugs and stay implicit.
1320
- const id = typeof o.id === 'string' && o.id !== '' && o.id !== outcomeSlug(name, idx) ? o.id : undefined;
1321
- // A bare string is the shorthand; `action: 'End'` or a kept id needs the object.
1322
- return o.action === 'End' || id !== undefined
1323
- ? opts([
1324
- ['name', tsLiteral(name)],
1325
- ['action', o.action === 'End' ? tsLiteral('End') : undefined],
1326
- ['id', id !== undefined ? tsLiteral(id) : undefined],
1327
- ])
1328
- : tsLiteral(name);
1329
- });
1330
- // Delivery: only an override comes back. The definition's own default is what
1331
- // serialize emits when the author wrote nothing.
1332
- const def = runDefs.get(`${node.type}@${node.typeVersion}`) ?? runDefs.get(node.type);
1333
- const defaultRecipient = JSON.stringify(def?.inputDefaults?.recipient ?? null);
1334
- const rec = i.recipient;
1335
- let recipientSrc;
1336
- if (rec !== undefined && JSON.stringify(rec) !== defaultRecipient) {
1337
- const assignee = (rec.assignee ?? {});
1338
- const channels = Array.isArray(rec.channels) ? rec.channels : undefined;
1339
- recipientSrc = opts([
1340
- ['channels', channels ? `[${channels.map((c) => tsLiteral(c)).join(', ')}]` : undefined],
1341
- ['assignee', opts([
1342
- ['type', tsLiteral(String(assignee.type ?? 'user'))],
1343
- ['value', typeof assignee.value === 'string' ? tsLiteral(assignee.value) : undefined],
1344
- ['displayName', typeof assignee.displayName === 'string' ? tsLiteral(assignee.displayName) : undefined],
1345
- ])],
1346
- ]);
1347
- }
1348
- // The deployed app that owns the form (action-app, and a custom-render
1349
- // validation station). `appInputBindings` maps the app's own parameter names
1350
- // to `=`-prefixed expressions.
1351
- const app = i.app;
1352
- // `app.inputs` is a VALUE map — what to send the app, keyed by the app's own
1353
- // parameter names — and it lowers to a SIBLING key, `appInputBindings`, whose
1354
- // values are `=vars.…` paths (or literals). Not a type map, and not inside
1355
- // `app`: both are easy to assume and both round-trip wrong.
1356
- const bindings = (i.appInputBindings ?? {});
1357
- const appInputs = Object.keys(bindings).length === 0 ? undefined : objLit(Object.entries(bindings).map(([k, v]) => {
1358
- const raw = String(v ?? '');
1359
- return [k, raw.startsWith('=') ? emitBareExpr(wireExprBody(raw), imp, inputNames) : tsLiteral(raw)];
1360
- }));
1361
- const appSrc = app === undefined ? undefined : opts([
1362
- // `displayName` is serialize's echo of `name`; only `name` is authored.
1363
- ['name', tsText(app.name)],
1364
- ['key', tsText(app.key)],
1365
- ['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ? tsLiteral(app.folderPath) : undefined],
1366
- ['appSystemName', app.appSystemName === null ? 'null'
1367
- : typeof app.appSystemName === 'string' ? tsLiteral(app.appSystemName) : undefined],
1368
- ['inputs', appInputs],
1369
- ]);
1370
- // The validation station's own inputs ride as PLAIN `$vars.…` paths. Anything
1371
- // but a `$vars.` reference stays the wire text verbatim.
1372
- const stationExpr = (v) => {
1373
- const raw = plain(v);
1374
- if (raw === undefined)
1375
- return undefined;
1376
- const js = wireExprBody(raw);
1377
- return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) : tsLiteral(raw);
1378
- };
1379
- const render = plain(i.validationRenderType);
1380
- const documentSrc = node.type !== T.hitlDocValidation ? undefined : opts([
1381
- ['extractionResult', stationExpr(i.extractionResult) ?? tsLiteral('')],
1382
- ['storageBucket', plain(i.storageBucket) !== undefined ? tsLiteral(plain(i.storageBucket)) : undefined],
1383
- ['documentId', plain(i.documentId) !== undefined ? tsLiteral(plain(i.documentId)) : undefined],
1384
- // 'standard' is the definition's default.
1385
- ['render', render !== undefined && render !== 'standard' ? tsLiteral(render) : undefined],
1386
- ['taxonomy', stationExpr(i.taxonomy)],
1387
- ]);
1388
- // On the base node the VERSION says it: 1.1 routes per outcome, 1.2 adds the
1389
- // error output (and implies the routing). Everywhere else — quick-form, a
1390
- // base task on 1.0 — the EDGES say it: outcomes that lead to different places
1391
- // are routed per outcome (`outcomePorts: true`, which a pinned 1.0 keeps at
1392
- // 1.0), and outcomes that all lead to one step are a fan-out, which the
1393
- // task's default recompiles to.
1394
- const version = String(node.typeVersion ?? '');
1395
- const exposeError = version === '1.2';
1396
- const outEdges = graph?.outEdges(node.id) ?? [];
1397
- const derivesHandles = OUTCOME_HANDLE_NODE_TYPES.has(String(node.type));
1398
- const outcomePorts = (node.type === T.hitl && version === '1.1')
1399
- || (derivesHandles && !versionRoutesHitl(node) && graph !== undefined && !graph.convergedFanOut(node.id)
1400
- && outEdges.some((e) => e.sourcePort.startsWith('outcome-')));
1401
- // A lone `completed` edge on a task with several outcomes is the shape the
1402
- // designer stopped drawing: before flow-workbench #3512 (09-08) it was
1403
- // unconditioned, so every outcome continued down it; since then Studio Web and
1404
- // the converter remap it to the primary outcome only. Recompiling writes one
1405
- // `outcome-<id>` edge per outcome to the same step — the first meaning — so
1406
- // this is the one place decompile→compile is deliberately not exact. Say so.
1407
- const legacyCompleted = derivesHandles && outcomeIdsOfNode(node).length > 1
1408
- && outEdges.some((e) => e.sourcePort === 'completed');
1409
- // Both a converged fan-out and a legacy lone `completed` mean "every outcome
1410
- // continues to the next step". Say so in the source with `outcomePorts: false`
1411
- // rather than leaving it to the `{ version }` pin, so the intent survives an
1412
- // author dropping the pin.
1413
- const fanOut = !outcomePorts && derivesHandles && !versionRoutesHitl(node) && outcomeIdsOfNode(node).length > 1
1414
- && (legacyCompleted || graph?.convergedFanOut(node.id) === true);
1415
- if (legacyCompleted) {
1416
- warnOnce(`human task ${tsLiteral(node.id)} leaves on the legacy 'completed' handle, which Studio Web no longer draws `
1417
- + `once a task has outcomes (it reads the edge as the primary outcome only). Recompiling emits one `
1418
- + `outcome-<id> edge per outcome to the same step, so every outcome continues — what the edge meant `
1419
- + `before flow-workbench #3512.`);
1420
- }
1421
- const title = plain(i.title);
1422
- const priority = plain(i.priority);
1423
- return `${imp.use('hitl')}(${opts([
1424
- ['variant', variant !== undefined ? tsLiteral(variant) : undefined],
1425
- // serialize defaults the title to the step's own name.
1426
- ['title', title !== undefined && title !== node.id ? tsLiteral(title) : undefined],
1427
- ['priority', priority !== undefined && priority !== 'Low' ? tsLiteral(priority) : undefined],
1428
- ['labels', plain(i.labels) !== undefined ? tsLiteral(plain(i.labels)) : undefined],
1429
- ['recipient', recipientSrc],
1430
- ['app', appSrc],
1431
- ['document', documentSrc],
1432
- // An app task and a validation station own no inline form; an empty array
1433
- // there is serialize's own, not the author's.
1434
- ['fields', fields.length ? `[${fields.join(', ')}]`
1435
- : (variant === 'action-app' || variant === 'document-validation') ? undefined : '[]'],
1436
- ['outcomes', `[${outcomes.join(', ')}]`],
1437
- ['outcomePorts', outcomePorts ? 'true' : fanOut ? 'false' : undefined],
1438
- ['exposeError', exposeError ? 'true' : undefined],
1439
- ])})`;
1440
- }
1441
1257
  /**
1442
1258
  * A connector EVENT subscription, shared by the trigger (`onEvent`) and the
1443
1259
  * mid-flow wait (`waitForEvent`) — the same node body in both places, so the
@@ -13,11 +13,12 @@ import { conversationFlowFamily } from './nodes/conversation/flow/family.js';
13
13
  import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
14
14
  import { delayFlowFamily } from './nodes/delay/flow/family.js';
15
15
  import { documentFlowFamily } from './nodes/document/flow/family.js';
16
+ import { hitlFlowFamily } from './nodes/hitl/flow/family.js';
16
17
  import { httpFlowFamily } from './nodes/http/flow/family.js';
17
18
  import { mockFlowFamily } from './nodes/mock/flow/family.js';
18
19
  import { queueFlowFamily } from './nodes/queue/flow/family.js';
19
20
  import { scriptFlowFamily } from './nodes/script/flow/family.js';
20
21
  import { transformFlowFamily } from './nodes/transform/flow/family.js';
21
22
  /** The families, in no significant order. Adding one is the whole of registering it. */
22
- export const FLOW_NODE_FAMILIES = [aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, httpFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
23
+ export const FLOW_NODE_FAMILIES = [aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, hitlFlowFamily, httpFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
23
24
  export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });
@@ -42,17 +42,40 @@ export interface FlowNodeContribution extends Omit<NodeContribution, 'definition
42
42
  model?: 'definition' | 'omit';
43
43
  /** The forward port the next step's edge leaves from. Default: the definition's default source handle. */
44
44
  port?: string;
45
+ /**
46
+ * Several forward ports, every one of which continues to the next step — a
47
+ * fan-out (a human task that does not route per outcome leaves on each
48
+ * outcome's handle). `endsRun` marks one the step list ends with an End
49
+ * instead (an `action: 'End'` outcome). Wins over `port`.
50
+ */
51
+ fanOut?: ReadonlyArray<{
52
+ readonly port: string;
53
+ readonly endsRun?: boolean;
54
+ }>;
55
+ /**
56
+ * `outputs` REPLACES the definition's `outputDefinition` on the node instead of
57
+ * being merged over it — for an instance whose output slots are its own (a
58
+ * human task's form decides them). Replaced outputs are written verbatim: no
59
+ * `{nodeId}` substitution, which a merged contribution's outputs get.
60
+ */
61
+ replaceOutputs?: boolean;
45
62
  }
46
63
  /** What `serialize` may ask of the serializer, for one placement. */
47
64
  export interface FlowSerializeContext {
48
65
  /** The step name the author gave this node. */
49
66
  readonly step: string;
67
+ /** The id this node is emitted under (rename-aware for a reused subflow copy). */
68
+ readonly nodeId: string;
69
+ /** The flow's id, as the file's top-level `id` carries it. */
70
+ readonly flowId: string;
50
71
  /**
51
72
  * The version being emitted, always set: the author's `{ version }` when the step
52
73
  * names one, else what `select()` or the default chose. It does not say whether
53
74
  * the author pinned it.
54
75
  */
55
76
  readonly version: string;
77
+ /** The author's `{ version }`, when the step names one; undefined when `select()` or the default chose. */
78
+ readonly pinnedVersion: string | undefined;
56
79
  /** Render one value (an `Expr`, or a literal) as the file stores it, with this scope's rename map. */
57
80
  render(value: unknown): unknown;
58
81
  /**
@@ -128,6 +151,17 @@ export interface FlowDeserializeContext {
128
151
  definition(): unknown;
129
152
  /** Report something the lift could not keep. Decompile prints it once. */
130
153
  warn(message: string): void;
154
+ /** The source ports this node's out-edges leave from, in edge order (an empty list outside a graph). */
155
+ outPorts(): readonly string[];
156
+ /**
157
+ * Whether this node is a human task (base or quick-form, not routing by its
158
+ * 1.1/1.2 version) whose every outcome in `inputs.schema.outcomes` is wired, all
159
+ * to ONE target, with no other exit edge: a fan-out that converges, which the
160
+ * source spells as continuing every outcome to the next step rather than as
161
+ * arms. The decompiler's graph answers it from the node's outcomes, not from
162
+ * the type's `exits()`, so it is `false` for any other node.
163
+ */
164
+ convergedFanOut(): boolean;
131
165
  }
132
166
  /** What `print` may ask of the decompiler. Every method returns source text. */
133
167
  export interface FlowPrintContext {
@@ -254,10 +288,20 @@ export interface FlowNodeType<Spec> extends NodeType<Spec, FlowNodeContribution,
254
288
  * and the port each leaves on — or why it has none to route. What
255
289
  * `.stepSwitch()` routes over, what an arm's `value` and a `.stepToList` port
256
290
  * are checked against, and what decompile reads a fully wired node back as.
291
+ * `pinnedVersion` is the author's `{ version }`, when the step names one: a
292
+ * human task's routing depends on whether it is pinned, not only on the version.
257
293
  * Omitted: the type has no author-declared fan-out. The `error` port is never
258
294
  * one of these (`.onError()` routes it).
259
295
  */
260
- exits?(spec: Spec): DeclaredExit[] | NoExits;
296
+ exits?(spec: Spec, pinnedVersion?: string): DeclaredExit[] | NoExits;
297
+ /**
298
+ * Whether `port` is a forward handle the PRODUCT derives for this spec, which
299
+ * the definition does not list — a human task's `outcome-<id>` handles, drawn
300
+ * from its outcomes at every version while the definition declares only
301
+ * `completed`. Serialize refuses a forward port that is neither declared by
302
+ * the definition, an exit of the type, nor derived.
303
+ */
304
+ derivesPort?(spec: Spec, port: string): boolean;
261
305
  }
262
306
  /** A Flow node type with several versions. */
263
307
  export type FlowVersionedNodeType<Spec> = VersionedNodeType<Spec, FlowNodeContribution, FlowContexts, FlowNodeType<Spec>>;
@@ -23,6 +23,7 @@ export * from './nodes/conversation/flow/index.js';
23
23
  export * from './nodes/data-fabric/flow/index.js';
24
24
  export * from './nodes/delay/flow/index.js';
25
25
  export * from './nodes/document/flow/index.js';
26
+ export * from './nodes/hitl/flow/index.js';
26
27
  export * from './nodes/http/flow/index.js';
27
28
  export * from './nodes/mock/flow/index.js';
28
29
  export * from './nodes/queue/flow/index.js';
package/dist/flow-sdk.js CHANGED
@@ -27,6 +27,7 @@ export * from './nodes/conversation/flow/index.js';
27
27
  export * from './nodes/data-fabric/flow/index.js';
28
28
  export * from './nodes/delay/flow/index.js';
29
29
  export * from './nodes/document/flow/index.js';
30
+ export * from './nodes/hitl/flow/index.js';
30
31
  export * from './nodes/http/flow/index.js';
31
32
  export * from './nodes/mock/flow/index.js';
32
33
  export * from './nodes/queue/flow/index.js';
@@ -26,5 +26,5 @@ export function stepExits(spec, pinnedVersion) {
26
26
  catch {
27
27
  impl = resolveVersion(entry.type, spec, undefined, 'exits');
28
28
  }
29
- return impl.exits?.(spec) ?? declaredExits(spec, pinnedVersion);
29
+ return impl.exits?.(spec, pinnedVersion) ?? declaredExits(spec, pinnedVersion);
30
30
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The HITL family's rules: the form, outcomes, variant and delivery of one human
3
+ * task (`checkHitl`), and a read of its result (`checkHitlRead`). Moved from
4
+ * check.ts in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; codes and
5
+ * messages unchanged. The rules that need the rest of the flow — an outcome no
6
+ * route takes, an outcome nothing downstream tells apart, a port the task does
7
+ * not draw — stay in check.ts, which walks the flow.
8
+ */
9
+ import type { DiagnosticCatalog } from '../../../core/nodes/family.js';
10
+ import type { OutputPathRead } from '../../../core/nodes/node-type.js';
11
+ import type { FlowCheckContext } from '../../../flow-node-type.js';
12
+ import type { HitlInputs } from './spec.js';
13
+ export declare const HITL_DIAGNOSTICS: DiagnosticCatalog;
14
+ /**
15
+ * A human task's form.
16
+ *
17
+ * Everything here is a mistake no later rung can see, which is the test for
18
+ * earning a place in `check` rather than in the docs: the flow compiles, deploys,
19
+ * and shows a person a form with something quietly missing from it. These catch it
20
+ * at rung 1, in the author's own vocabulary.
21
+ */
22
+ export declare function checkHitl(inputs: HitlInputs, ctx: FlowCheckContext): void;
23
+ /**
24
+ * A read of a human task's output: `out('<step>', '<field>')`.
25
+ *
26
+ * The node publishes an object keyed by the form's ANSWER fields plus `Action`.
27
+ * Two mistakes are silent at run time and both are caught here:
28
+ *
29
+ * - reading a field the form does not answer (a shown field, or a typo) —
30
+ * `undefined`, offline and deployed;
31
+ * - reading `$vars.<step>.status`, the platform's own projection of the chosen
32
+ * outcome. It resolves *deployed*, so the flow works in production and reads
33
+ * `undefined` on this SDK's offline rungs — a divergence, which is why the read
34
+ * is redirected rather than merely flagged. (A runner that derives declared
35
+ * output variables resolves `status` offline as well; the surface still points
36
+ * at one spelling so a flow reads the same everywhere.)
37
+ */
38
+ export declare function checkHitlRead({ node: name, field, rest, reader: step }: OutputPathRead, form: HitlInputs | undefined, report: (code: string, message: string, suggestion?: string) => void): void;