@uipath/maestro-builder-sdk 6.19.0 → 6.20.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 (41) hide show
  1. package/dist/api-index.md +107 -107
  2. package/dist/api-members.md +358 -356
  3. package/dist/check.js +181 -45
  4. package/dist/cli/commands/flow.js +3 -0
  5. package/dist/compile-cli.js +51 -0
  6. package/dist/core/actions.d.ts +13 -5
  7. package/dist/core/actions.js +1 -1
  8. package/dist/core/binding-identity.d.ts +22 -0
  9. package/dist/core/binding-identity.js +28 -0
  10. package/dist/core/context-index.d.ts +34 -0
  11. package/dist/core/context-index.js +38 -0
  12. package/dist/core/definitionless-node-types.d.ts +16 -0
  13. package/dist/core/definitionless-node-types.js +16 -0
  14. package/dist/core/form-field-type.d.ts +33 -0
  15. package/dist/core/form-field-type.js +30 -0
  16. package/dist/core/hitl-routing.d.ts +8 -0
  17. package/dist/core/hitl-routing.js +17 -1
  18. package/dist/core/process-resource-sort-order.d.ts +40 -0
  19. package/dist/core/process-resource-sort-order.js +44 -0
  20. package/dist/core/wire-expr.d.ts +27 -0
  21. package/dist/core/wire-expr.js +34 -0
  22. package/dist/decompile-cli.js +11 -1
  23. package/dist/decompile.d.ts +8 -3
  24. package/dist/decompile.js +680 -104
  25. package/dist/flow-expr-check.js +1 -1
  26. package/dist/flow-sdk.d.ts +33 -1
  27. package/dist/flow-sdk.js +21 -2
  28. package/dist/flow-step-tree.js +2 -1
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.js +1 -0
  31. package/dist/merge-cli.js +25 -8
  32. package/dist/merge-roundtrip.d.ts +81 -0
  33. package/dist/merge-roundtrip.js +404 -0
  34. package/dist/merge.d.ts +35 -6
  35. package/dist/merge.js +124 -24
  36. package/dist/node-placement.d.ts +93 -0
  37. package/dist/node-placement.js +163 -0
  38. package/dist/nodes/transform/flow/node-type.js +2 -1
  39. package/dist/registry/uip/pipeline-front-door.js +5 -3
  40. package/dist/serialize.js +112 -61
  41. package/package.json +2 -2
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A context-grounding index's node type, both ways.
3
+ *
4
+ * The platform names an index's resource node
5
+ * `uipath.agent.resource.context.index.<slug>.<uuid>`: the slug is derived from
6
+ * the index's display name, and the uuid is the index's id. Serialize builds the
7
+ * type from an author's `{ name, id }`; decompile reads `{ slug, id }` back out
8
+ * of a file's type. Keeping both directions here is what keeps them inverses.
9
+ */
10
+ /** The type prefix every context-index resource node shares. */
11
+ export declare const CONTEXT_INDEX_TYPE_PREFIX = "uipath.agent.resource.context.index.";
12
+ /**
13
+ * The slug for an index name: lower-cased, with every run of non-alphanumerics
14
+ * collapsed to a single `-`. Measured against the platform's own type for
15
+ * "Billing Dispute SOP Index" → `billing-dispute-sop-index`, and pinned by a
16
+ * test, because a derived identifier that disagrees with the registry's is a
17
+ * node type the tenant has never heard of. A slug never contains a `.`.
18
+ */
19
+ export declare function contextIndexSlug(name: string): string;
20
+ /** The node type for an index: `…context.index.<slug>.<uuid>`. */
21
+ export declare function contextIndexType(spec: {
22
+ name: string;
23
+ id: string;
24
+ }): string;
25
+ /**
26
+ * The `{ slug, id }` a context-index node type carries, or `undefined` when the
27
+ * type is not one. The id is everything after the LAST `.`, because a slug has
28
+ * no dot in it. Either part can be `''` (the SDK once wrote `…<slug>.` for an
29
+ * index with no id).
30
+ */
31
+ export declare function parseContextIndexType(type: string): {
32
+ slug: string;
33
+ id: string;
34
+ } | undefined;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A context-grounding index's node type, both ways.
3
+ *
4
+ * The platform names an index's resource node
5
+ * `uipath.agent.resource.context.index.<slug>.<uuid>`: the slug is derived from
6
+ * the index's display name, and the uuid is the index's id. Serialize builds the
7
+ * type from an author's `{ name, id }`; decompile reads `{ slug, id }` back out
8
+ * of a file's type. Keeping both directions here is what keeps them inverses.
9
+ */
10
+ /** The type prefix every context-index resource node shares. */
11
+ export const CONTEXT_INDEX_TYPE_PREFIX = 'uipath.agent.resource.context.index.';
12
+ /**
13
+ * The slug for an index name: lower-cased, with every run of non-alphanumerics
14
+ * collapsed to a single `-`. Measured against the platform's own type for
15
+ * "Billing Dispute SOP Index" → `billing-dispute-sop-index`, and pinned by a
16
+ * test, because a derived identifier that disagrees with the registry's is a
17
+ * node type the tenant has never heard of. A slug never contains a `.`.
18
+ */
19
+ export function contextIndexSlug(name) {
20
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
21
+ }
22
+ /** The node type for an index: `…context.index.<slug>.<uuid>`. */
23
+ export function contextIndexType(spec) {
24
+ return `${CONTEXT_INDEX_TYPE_PREFIX}${contextIndexSlug(spec.name)}.${spec.id}`;
25
+ }
26
+ /**
27
+ * The `{ slug, id }` a context-index node type carries, or `undefined` when the
28
+ * type is not one. The id is everything after the LAST `.`, because a slug has
29
+ * no dot in it. Either part can be `''` (the SDK once wrote `…<slug>.` for an
30
+ * index with no id).
31
+ */
32
+ export function parseContextIndexType(type) {
33
+ if (!type.startsWith(CONTEXT_INDEX_TYPE_PREFIX))
34
+ return undefined;
35
+ const tail = type.slice(CONTEXT_INDEX_TYPE_PREFIX.length);
36
+ const dot = tail.lastIndexOf('.');
37
+ return dot < 0 ? { slug: tail, id: '' } : { slug: tail.slice(0, dot), id: tail.slice(dot + 1) };
38
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Node types that never have a `definitions[]` row.
3
+ *
4
+ * A `.flow` file pairs every node's `(type, typeVersion)` with a definition —
5
+ * except these. The platform special-cases them ahead of definition resolution:
6
+ * a sticky note has no manifest, `flow validate` skips it, BPMN conversion skips
7
+ * it, and an edge that touches one is dropped. So "this node pins a pair no
8
+ * definition covers" is a real defect for every other type and the normal state
9
+ * for these.
10
+ */
11
+ /** The wire type of a canvas sticky note. */
12
+ export declare const STICKY_NOTE_TYPE = "stickyNote";
13
+ /** The `typeVersion` Studio Web stamps on a sticky note. The type has no manifest to take it from. */
14
+ export declare const STICKY_NOTE_TYPE_VERSION = "1.0.0";
15
+ /** Node types that carry no definition by design. */
16
+ export declare const DEFINITIONLESS_NODE_TYPES: ReadonlySet<string>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Node types that never have a `definitions[]` row.
3
+ *
4
+ * A `.flow` file pairs every node's `(type, typeVersion)` with a definition —
5
+ * except these. The platform special-cases them ahead of definition resolution:
6
+ * a sticky note has no manifest, `flow validate` skips it, BPMN conversion skips
7
+ * it, and an edge that touches one is dropped. So "this node pins a pair no
8
+ * definition covers" is a real defect for every other type and the normal state
9
+ * for these.
10
+ */
11
+ /** The wire type of a canvas sticky note. */
12
+ export const STICKY_NOTE_TYPE = 'stickyNote';
13
+ /** The `typeVersion` Studio Web stamps on a sticky note. The type has no manifest to take it from. */
14
+ export const STICKY_NOTE_TYPE_VERSION = '1.0.0';
15
+ /** Node types that carry no definition by design. */
16
+ export const DEFINITIONLESS_NODE_TYPES = new Set([STICKY_NOTE_TYPE]);
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The product's spellings of the form-field types the SDK models.
3
+ *
4
+ * A quick form's field `type` is read by the product through
5
+ * `@uipath/hitl-schema-types` `normalizeFieldType`. Its canonical stored values
6
+ * are `string`, `number`, `boolean`, `datetime`, … and it accepts aliases for
7
+ * each: `text` is an alias of `string`, `date-time` of `datetime`, and .NET
8
+ * names such as `System.String` resolve too. The designer saves the canonical
9
+ * value, so a canvas-built form says `"string"`; the SDK (like flow-v1's
10
+ * serializer and `uip maestro flow hitl add`) writes `text`.
11
+ *
12
+ * So `"string"` and `"text"` are the same field on the wire. This table maps
13
+ * each product spelling of the four types {@link FormFieldType} models to the
14
+ * SDK's spelling, so decompile hands the author source `check` accepts.
15
+ * A type the SDK does not model (`integer`, `date`,
16
+ * `file`, …) has no entry: it stays as written, and `check` reports it.
17
+ *
18
+ * Mirrors `resolveFieldType` in `@uipath/hitl-schema-types` 1.1.6, restricted
19
+ * to the groups that resolve to `string`, `number`, `boolean` and `datetime`
20
+ * (minus `singleSelect` / `enum` / `union` / …, which resolve to `string` but
21
+ * are not a plain text box).
22
+ */
23
+ import type { FormFieldType } from './actions.js';
24
+ /**
25
+ * The SDK's spelling of a wire form-field type, or `undefined` when the SDK
26
+ * does not model that type.
27
+ *
28
+ * @example
29
+ * sdkFormFieldType('string') // 'text'
30
+ * sdkFormFieldType('datetime') // 'date-time'
31
+ * sdkFormFieldType('integer') // undefined
32
+ */
33
+ export declare function sdkFormFieldType(wire: unknown): FormFieldType | undefined;
@@ -0,0 +1,30 @@
1
+ const PRODUCT_SPELLINGS = {
2
+ text: 'text',
3
+ string: 'text',
4
+ String: 'text',
5
+ 'System.String': 'text',
6
+ 'System.Char': 'text',
7
+ Char: 'text',
8
+ number: 'number',
9
+ Number: 'number',
10
+ boolean: 'boolean',
11
+ Boolean: 'boolean',
12
+ 'System.Boolean': 'boolean',
13
+ 'date-time': 'date-time',
14
+ datetime: 'date-time',
15
+ dateTime: 'date-time',
16
+ DateTime: 'date-time',
17
+ 'System.DateTime': 'date-time',
18
+ };
19
+ /**
20
+ * The SDK's spelling of a wire form-field type, or `undefined` when the SDK
21
+ * does not model that type.
22
+ *
23
+ * @example
24
+ * sdkFormFieldType('string') // 'text'
25
+ * sdkFormFieldType('datetime') // 'date-time'
26
+ * sdkFormFieldType('integer') // undefined
27
+ */
28
+ export function sdkFormFieldType(wire) {
29
+ return typeof wire === 'string' && Object.hasOwn(PRODUCT_SPELLINGS, wire) ? PRODUCT_SPELLINGS[wire] : undefined;
30
+ }
@@ -79,6 +79,14 @@ import type { HitlInputs } from './actions.js';
79
79
  * nothing else recognises.
80
80
  */
81
81
  export declare function outcomeSlug(name: unknown, index: number): string;
82
+ /**
83
+ * The id an outcome is emitted with: the author's `id` when the object form
84
+ * carries one (a decompiled flow keeps the canvas's ids, for example
85
+ * `outcome-1778015958049`), else {@link outcomeSlug} of its name. Every reader
86
+ * of outcome ids goes through this, so the `outcome-<id>` port an edge leaves
87
+ * from and the id `schema.outcomes[]` declares cannot disagree (#1130).
88
+ */
89
+ export declare function outcomeIdOf(outcome: unknown, index: number): string;
82
90
  /** One outcome's exit. */
83
91
  export interface HitlOutcomeExit {
84
92
  /** The outcome NAME — what `.stepSwitch` arms and `out('<step>', 'Action')` compare against. */
@@ -14,6 +14,22 @@ export function outcomeSlug(name, index) {
14
14
  .replace(/^-+|-+$/g, '');
15
15
  return slug || `outcome-${index + 1}`;
16
16
  }
17
+ /**
18
+ * The id an outcome is emitted with: the author's `id` when the object form
19
+ * carries one (a decompiled flow keeps the canvas's ids, for example
20
+ * `outcome-1778015958049`), else {@link outcomeSlug} of its name. Every reader
21
+ * of outcome ids goes through this, so the `outcome-<id>` port an edge leaves
22
+ * from and the id `schema.outcomes[]` declares cannot disagree (#1130).
23
+ */
24
+ export function outcomeIdOf(outcome, index) {
25
+ if (outcome !== null && typeof outcome === 'object') {
26
+ const { id, name } = outcome;
27
+ if (typeof id === 'string' && id !== '')
28
+ return id;
29
+ return outcomeSlug(name, index);
30
+ }
31
+ return outcomeSlug(outcome, index);
32
+ }
17
33
  /**
18
34
  * The two human-task node types whose exits the product derives from
19
35
  * `inputs.schema.outcomes`. Keyed on TYPE, never on whether `schema.outcomes` is
@@ -33,7 +49,7 @@ export function hitlExitModel(inputs, pinnedVersion) {
33
49
  const name = typeof o === 'string' ? o : o?.name;
34
50
  return {
35
51
  value: String(name ?? ''),
36
- port: `outcome-${outcomeSlug(name, i)}`,
52
+ port: `outcome-${outcomeIdOf(o, i)}`,
37
53
  endsProcess: typeof o !== 'string' && o?.action === 'End',
38
54
  };
39
55
  });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The palette `sortOrder` of a process-resource node (an RPA workflow, API
3
+ * workflow, function, agent, or agentic process, published or in-solution),
4
+ * derived the way the platform derives it.
5
+ *
6
+ * flow-core's `buildNodeManifest` (`@uipath/flow-core/manifest`) does not keep a
7
+ * per-family number. It writes `categorySortOrders[baseCategory] +
8
+ * DYNAMIC_NODE_SORT_OFFSET`, where `baseCategory` is the resource type's category
9
+ * (`agent`, `flow`, …) before any `published` / `in-solution` listing suffix. So
10
+ * this module keeps the same two inputs and the same sum, not five literals.
11
+ *
12
+ * The base values are flow-core 0.115.4's `baseCategorySortOrders` for these
13
+ * categories (read 2026-10-08). They match what the platform writes today:
14
+ * `registry get` on alpha/codereval returns agent 510, flow 600, agentic-process
15
+ * 610, case-management 620, rpa-workflow 630, api-workflow 640, function 650, and
16
+ * 54 of 54 v1 in-solution agent `.flow` files (09-01 to 10-08) carry 510.
17
+ *
18
+ * flow-core renumbered these once already (agent was 5, api-workflow 10,
19
+ * rpa-workflow 30). `tests/process-resource-sort-order.test.ts` compares this
20
+ * table with a local flow-core when one is present, so the next renumber shows
21
+ * up as a red test rather than as a silent diff.
22
+ */
23
+ export declare const PROCESS_RESOURCE_CATEGORY_SORT_ORDERS: {
24
+ readonly agent: 10;
25
+ readonly flow: 100;
26
+ readonly 'agentic-process': 110;
27
+ readonly 'case-management': 120;
28
+ readonly 'rpa-workflow': 130;
29
+ readonly 'api-workflow': 140;
30
+ readonly function: 150;
31
+ };
32
+ /** flow-core's `DYNAMIC_NODE_SORT_OFFSET`: every tenant-built node sorts after every static one. */
33
+ export declare const DYNAMIC_NODE_SORT_OFFSET = 500;
34
+ /** A process-resource node category, e.g. `'agent'` or `'rpa-workflow'`. */
35
+ export type ProcessResourceCategory = keyof typeof PROCESS_RESOURCE_CATEGORY_SORT_ORDERS;
36
+ /**
37
+ * The `sortOrder` the platform writes for a process-resource node of this
38
+ * category. For instance `resourceNodeSortOrder('agent')` is 510.
39
+ */
40
+ export declare function resourceNodeSortOrder(category: ProcessResourceCategory): number;
@@ -0,0 +1,44 @@
1
+ import { ownEntry } from './own-entry.js';
2
+ /**
3
+ * The palette `sortOrder` of a process-resource node (an RPA workflow, API
4
+ * workflow, function, agent, or agentic process, published or in-solution),
5
+ * derived the way the platform derives it.
6
+ *
7
+ * flow-core's `buildNodeManifest` (`@uipath/flow-core/manifest`) does not keep a
8
+ * per-family number. It writes `categorySortOrders[baseCategory] +
9
+ * DYNAMIC_NODE_SORT_OFFSET`, where `baseCategory` is the resource type's category
10
+ * (`agent`, `flow`, …) before any `published` / `in-solution` listing suffix. So
11
+ * this module keeps the same two inputs and the same sum, not five literals.
12
+ *
13
+ * The base values are flow-core 0.115.4's `baseCategorySortOrders` for these
14
+ * categories (read 2026-10-08). They match what the platform writes today:
15
+ * `registry get` on alpha/codereval returns agent 510, flow 600, agentic-process
16
+ * 610, case-management 620, rpa-workflow 630, api-workflow 640, function 650, and
17
+ * 54 of 54 v1 in-solution agent `.flow` files (09-01 to 10-08) carry 510.
18
+ *
19
+ * flow-core renumbered these once already (agent was 5, api-workflow 10,
20
+ * rpa-workflow 30). `tests/process-resource-sort-order.test.ts` compares this
21
+ * table with a local flow-core when one is present, so the next renumber shows
22
+ * up as a red test rather than as a silent diff.
23
+ */
24
+ export const PROCESS_RESOURCE_CATEGORY_SORT_ORDERS = {
25
+ agent: 10,
26
+ flow: 100,
27
+ 'agentic-process': 110,
28
+ 'case-management': 120,
29
+ 'rpa-workflow': 130,
30
+ 'api-workflow': 140,
31
+ function: 150,
32
+ };
33
+ /** flow-core's `DYNAMIC_NODE_SORT_OFFSET`: every tenant-built node sorts after every static one. */
34
+ export const DYNAMIC_NODE_SORT_OFFSET = 500;
35
+ /**
36
+ * The `sortOrder` the platform writes for a process-resource node of this
37
+ * category. For instance `resourceNodeSortOrder('agent')` is 510.
38
+ */
39
+ export function resourceNodeSortOrder(category) {
40
+ const base = ownEntry(PROCESS_RESOURCE_CATEGORY_SORT_ORDERS, category);
41
+ if (base === undefined)
42
+ throw new Error(`no sortOrder for process-resource category '${category}'`);
43
+ return base + DYNAMIC_NODE_SORT_OFFSET;
44
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * core/wire-expr — reading an expression back out of the wire format.
3
+ *
4
+ * Shared by decompile and by every node family's deserializer, so the set of
5
+ * accepted spellings lives in one place.
6
+ */
7
+ /**
8
+ * The JS body of a value in an EXPRESSION SLOT: a field that always holds an
9
+ * expression and never literal text (a branch condition, a loop collection, an
10
+ * agent input binding, an app input binding, a field binding).
11
+ *
12
+ * The wire format has more than one spelling for one expression there, and this
13
+ * is the one place that knows them all:
14
+ *
15
+ * - `=js:<body>` -- what SDK compile writes.
16
+ * - `=<body>` (bare `=`) -- what the product writes for bindings: the CLI's
17
+ * agent-input encoder emits `=$vars.<node>.output.<field>` (uipath-cli
18
+ * `agent-input-encoding-utils.ts`), and `=$metadata.<key>` the same way.
19
+ * - `=vars.<path>` / `=metadata.<path>` -- the PATH form flow-v1 writes for app
20
+ * and field bindings. It names the same variable the SDK spells `$vars.<path>`.
21
+ * - no prefix -- the slot stores a bare JS body (decision/switch conditions).
22
+ *
23
+ * A VALUE slot (an ordinary node input) is different: there only `=js:` marks an
24
+ * expression and any other string is literal text, as the product reads it
25
+ * (flow-schema `coerceToExpressionValue`). Do not use this for one.
26
+ */
27
+ export declare function wireExprBody(raw: string): string;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * core/wire-expr — reading an expression back out of the wire format.
3
+ *
4
+ * Shared by decompile and by every node family's deserializer, so the set of
5
+ * accepted spellings lives in one place.
6
+ */
7
+ /**
8
+ * The JS body of a value in an EXPRESSION SLOT: a field that always holds an
9
+ * expression and never literal text (a branch condition, a loop collection, an
10
+ * agent input binding, an app input binding, a field binding).
11
+ *
12
+ * The wire format has more than one spelling for one expression there, and this
13
+ * is the one place that knows them all:
14
+ *
15
+ * - `=js:<body>` -- what SDK compile writes.
16
+ * - `=<body>` (bare `=`) -- what the product writes for bindings: the CLI's
17
+ * agent-input encoder emits `=$vars.<node>.output.<field>` (uipath-cli
18
+ * `agent-input-encoding-utils.ts`), and `=$metadata.<key>` the same way.
19
+ * - `=vars.<path>` / `=metadata.<path>` -- the PATH form flow-v1 writes for app
20
+ * and field bindings. It names the same variable the SDK spells `$vars.<path>`.
21
+ * - no prefix -- the slot stores a bare JS body (decision/switch conditions).
22
+ *
23
+ * A VALUE slot (an ordinary node input) is different: there only `=js:` marks an
24
+ * expression and any other string is literal text, as the product reads it
25
+ * (flow-schema `coerceToExpressionValue`). Do not use this for one.
26
+ */
27
+ export function wireExprBody(raw) {
28
+ if (raw.startsWith('=js:'))
29
+ return raw.slice(4);
30
+ if (!raw.startsWith('='))
31
+ return raw;
32
+ const body = raw.slice(1);
33
+ return /^(?:vars|metadata)(?:\.[A-Za-z_$][\w$]*|\[\d+\])*$/.test(body.trim()) ? `$${body.trim()}` : body;
34
+ }
@@ -129,7 +129,17 @@ if (!existsSync(BASELINE)) {
129
129
  // ask for confirmation before the write. Left as a no-op for now.
130
130
  // ---------------------------------------------------------------------------
131
131
 
132
- const args = [ORIGINAL, EDITED, '-o', MERGED];
132
+ // \`merge <edited> --original <original>\` is the grammar; the positional
133
+ // \`merge <original> <edited>\` pair is deprecated. A \`uip\` from before
134
+ // UiPath/cli#4526 knows only the pair, so ask its \`merge --help\` first.
135
+ // Key on the door, not the file name: on Windows \`uip\` resolves to node.exe
136
+ // or a full uip.exe path.
137
+ const mergeHelp = frontDoor.via === 'uip'
138
+ ? spawnSync(frontDoor.file, [...frontDoor.prefix, 'merge', '--help'], { encoding: 'utf8' })
139
+ : undefined;
140
+ const namedOriginal = mergeHelp === undefined
141
+ || \`\${mergeHelp.stdout ?? ''}\${mergeHelp.stderr ?? ''}\`.includes('--original');
142
+ const args = namedOriginal ? [EDITED, '--original', ORIGINAL, '-o', MERGED] : [ORIGINAL, EDITED, '-o', MERGED];
133
143
  if (existsSync(BASELINE)) args.push('--baseline', BASELINE);
134
144
  run('merge', args);
135
145
  console.log('\\n>>> Wrote ' + ${JSON.stringify(base + '.merged.flow')});
@@ -128,9 +128,11 @@ export interface DecompileOptions {
128
128
  /**
129
129
  * Receives each non-fatal finding about the file, one message per finding:
130
130
  * a node no trigger reaches (the builder cannot express a detached node, so
131
- * the source omits it — strict mode throws instead), and a core
132
- * `(type, typeVersion)` pair this SDK does not bundle (the source keeps it;
133
- * `compile` will refuse it). The CLI prints these on stderr.
131
+ * the source omits it — strict mode throws instead), and a
132
+ * `(type, typeVersion)` pair this SDK cannot resolve for a type it ships at
133
+ * other versions (the source omits that `{ version }`, so the node compiles at
134
+ * the SDK's default; `merge` with a baseline keeps the untouched original
135
+ * node at its version — strict mode throws instead). The CLI prints these on stderr.
134
136
  */
135
137
  warn?: (message: string) => void;
136
138
  /**
@@ -142,6 +144,9 @@ export interface DecompileOptions {
142
144
  * (`{{input.start__output__notes}}`), so the recovered source declares its
143
145
  * inputs under those names — the same flow, not the same spelling. Without a
144
146
  * reader, a shell agent decompiles with empty prompts and a warning.
147
+ * A context index placed by the canvas or the CLI keeps its real name and
148
+ * folder only in `<agent source>/resources/<inputs.source>/resource.json`,
149
+ * which is read the same way.
145
150
  */
146
151
  readSidecar?: (relativePath: string) => string | undefined;
147
152
  }