@styx-api/core 0.1.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.
Files changed (88) hide show
  1. package/dist/index.cjs +7947 -0
  2. package/dist/index.d.cts +1143 -0
  3. package/dist/index.d.cts.map +1 -0
  4. package/dist/index.d.mts +1143 -0
  5. package/dist/index.d.mts.map +1 -0
  6. package/dist/index.mjs +7877 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +55 -0
  9. package/src/backend/backend.ts +95 -0
  10. package/src/backend/boutiques/boutiques.ts +1049 -0
  11. package/src/backend/boutiques/index.ts +1 -0
  12. package/src/backend/code-builder.ts +49 -0
  13. package/src/backend/collect-field-info.ts +50 -0
  14. package/src/backend/collect-named-types.ts +103 -0
  15. package/src/backend/collect-output-fields.ts +222 -0
  16. package/src/backend/find-doc.ts +38 -0
  17. package/src/backend/find-struct-node.ts +66 -0
  18. package/src/backend/index.ts +39 -0
  19. package/src/backend/python/arg-builder.ts +454 -0
  20. package/src/backend/python/emit.ts +638 -0
  21. package/src/backend/python/index.ts +9 -0
  22. package/src/backend/python/outputs-emit.ts +430 -0
  23. package/src/backend/python/packaging.ts +173 -0
  24. package/src/backend/python/python.ts +558 -0
  25. package/src/backend/python/snippet.ts +84 -0
  26. package/src/backend/python/typemap.ts +131 -0
  27. package/src/backend/python/types.ts +8 -0
  28. package/src/backend/python/validate-emit.ts +356 -0
  29. package/src/backend/resolve-field-binding.ts +41 -0
  30. package/src/backend/resolve-output-tokens.ts +80 -0
  31. package/src/backend/schema/index.ts +2 -0
  32. package/src/backend/schema/jsonschema.ts +303 -0
  33. package/src/backend/scope.ts +50 -0
  34. package/src/backend/sig-entries.ts +97 -0
  35. package/src/backend/snippet-core.ts +185 -0
  36. package/src/backend/string-case.ts +30 -0
  37. package/src/backend/styxdefs-compat.ts +21 -0
  38. package/src/backend/type-keys.ts +52 -0
  39. package/src/backend/typescript/arg-builder.ts +420 -0
  40. package/src/backend/typescript/emit.ts +450 -0
  41. package/src/backend/typescript/index.ts +10 -0
  42. package/src/backend/typescript/outputs-emit.ts +389 -0
  43. package/src/backend/typescript/packaging.ts +130 -0
  44. package/src/backend/typescript/snippet.ts +60 -0
  45. package/src/backend/typescript/typemap.ts +47 -0
  46. package/src/backend/typescript/types.ts +8 -0
  47. package/src/backend/typescript/typescript.ts +507 -0
  48. package/src/backend/typescript/validate-emit.ts +341 -0
  49. package/src/backend/union-variants.ts +42 -0
  50. package/src/backend/validate-walk.ts +111 -0
  51. package/src/bindings/binding.ts +77 -0
  52. package/src/bindings/format.ts +176 -0
  53. package/src/bindings/index.ts +16 -0
  54. package/src/bindings/output-gate.ts +50 -0
  55. package/src/bindings/resolved-output.ts +56 -0
  56. package/src/bindings/types.ts +16 -0
  57. package/src/frontend/argdump/index.ts +1 -0
  58. package/src/frontend/argdump/parser.ts +914 -0
  59. package/src/frontend/boutiques/destruct-template.ts +50 -0
  60. package/src/frontend/boutiques/index.ts +1 -0
  61. package/src/frontend/boutiques/parser.ts +676 -0
  62. package/src/frontend/boutiques/split-command.ts +69 -0
  63. package/src/frontend/detect-format.ts +42 -0
  64. package/src/frontend/frontend.ts +31 -0
  65. package/src/frontend/index.ts +9 -0
  66. package/src/frontend/workbench/index.ts +1 -0
  67. package/src/frontend/workbench/parser.ts +351 -0
  68. package/src/index.ts +41 -0
  69. package/src/ir/builders.ts +69 -0
  70. package/src/ir/format.ts +157 -0
  71. package/src/ir/index.ts +32 -0
  72. package/src/ir/meta.ts +91 -0
  73. package/src/ir/node.ts +95 -0
  74. package/src/ir/passes/canonicalize.ts +108 -0
  75. package/src/ir/passes/flatten.ts +73 -0
  76. package/src/ir/passes/index.ts +7 -0
  77. package/src/ir/passes/pass.ts +86 -0
  78. package/src/ir/passes/pipeline.ts +21 -0
  79. package/src/ir/passes/remove-empty.ts +76 -0
  80. package/src/ir/passes/simplify.ts +179 -0
  81. package/src/ir/types.ts +15 -0
  82. package/src/manifest/context.ts +36 -0
  83. package/src/manifest/index.ts +3 -0
  84. package/src/manifest/types.ts +15 -0
  85. package/src/solver/assign-access.ts +218 -0
  86. package/src/solver/index.ts +4 -0
  87. package/src/solver/resolve-outputs.ts +233 -0
  88. package/src/solver/solver.ts +319 -0
@@ -0,0 +1,1143 @@
1
+ //#region src/frontend/detect-format.d.ts
2
+ type FormatName = "boutiques" | "argdump" | "workbench";
3
+ /**
4
+ * Auto-detect the format of a JSON descriptor source string.
5
+ * Returns null if the format cannot be determined.
6
+ */
7
+ declare function detectFormat(source: string): FormatName | null;
8
+ //#endregion
9
+ //#region src/ir/types.d.ts
10
+ /** Scalar type kinds for terminal nodes */
11
+ type ScalarKind = "int" | "float" | "str" | "path";
12
+ /** Media type identifier (MIME type) */
13
+ type MediaTypeIdentifier = string;
14
+ /** Human-facing documentation metadata */
15
+ interface Documentation {
16
+ title?: string;
17
+ description?: string;
18
+ authors?: string[];
19
+ literature?: string[];
20
+ urls?: string[];
21
+ comment?: string;
22
+ }
23
+ //#endregion
24
+ //#region src/ir/meta.d.ts
25
+ /**
26
+ * Opaque, name-based reference to an IR node by its `NodeMeta.name`.
27
+ *
28
+ * Resolved post-solve against the binding registry, not within IR passes.
29
+ * Names survive optimization (pointers don't), so token refs stay valid even
30
+ * after passes rewrite the tree. See `memory/design_outputs.md`.
31
+ */
32
+ interface NodeRef {
33
+ kind: "node-ref";
34
+ name: string;
35
+ }
36
+ /** Construct a NodeRef from a node name. */
37
+ declare function nodeRef(name: string): NodeRef;
38
+ /** Output token: literal text or a parameter reference. */
39
+ type OutputToken = {
40
+ kind: "literal";
41
+ value: string;
42
+ } | {
43
+ kind: "ref";
44
+ target: NodeRef;
45
+ stripExtensions?: string[];
46
+ fallback?: string;
47
+ };
48
+ /**
49
+ * Specification for a file the tool produces. Lives on `NodeMeta.outputs` of
50
+ * the struct node (root sequence or subcommand sequence) that declared it.
51
+ * Per-output gating is derived downstream from the scope's binding gate and
52
+ * each ref binding's gate, so no host node or `optional` flag is stored.
53
+ */
54
+ interface Output {
55
+ name?: string;
56
+ doc?: Documentation;
57
+ tokens: OutputToken[];
58
+ mediaTypes?: MediaTypeIdentifier[];
59
+ }
60
+ /** Metadata attached to any IR node. */
61
+ interface NodeMeta {
62
+ /** Name identifier for this node (used by solver for binding names). */
63
+ name?: string;
64
+ /**
65
+ * The discriminator (`@type`) tag for this node when it is a union arm (a
66
+ * Boutiques sub-command). Kept separate from `name`: a single-field
67
+ * sub-command collapses onto its inner field, whose `name` then wins, so the
68
+ * tag would otherwise become the inner field's id - e.g. two distinct
69
+ * sub-commands `VariousString`/`VariousFile` both wrapping an `obj` field
70
+ * would collide on `@type: "obj"` (and the second arm would be unreachable).
71
+ * `mergeMeta` preserves this through the collapse and the solver prefers it
72
+ * for the variant tag, so distinct sub-commands keep distinct, reachable
73
+ * `@type`s.
74
+ */
75
+ variantTag?: string;
76
+ doc?: Documentation;
77
+ defaultValue?: string | number | boolean;
78
+ /** Files produced when this node is active. See `Output`. */
79
+ outputs?: Output[];
80
+ }
81
+ /** Application-level metadata for the root node. */
82
+ interface AppMeta {
83
+ id?: string;
84
+ version?: string;
85
+ doc?: Documentation;
86
+ container?: {
87
+ image: string;
88
+ type?: "docker" | "singularity";
89
+ };
90
+ stdout?: StreamOutput;
91
+ stderr?: StreamOutput;
92
+ }
93
+ interface StreamOutput {
94
+ name: string;
95
+ doc?: Documentation;
96
+ }
97
+ /**
98
+ * Produce a usable name for an Output. Frontends may leave `Output.name`
99
+ * unset; downstream code (resolver, validator, backends) needs a stable
100
+ * identifier for diagnostics and field naming. Falls back to `output_<index>`
101
+ * keyed by the output's position in tree-walk order.
102
+ */
103
+ declare function effectiveOutputName(output: Output, index: number): string;
104
+ //#endregion
105
+ //#region src/ir/node.d.ts
106
+ /** Base structure for all IR nodes */
107
+ interface BaseNode<K extends string, Attrs> {
108
+ kind: K;
109
+ meta?: NodeMeta;
110
+ attrs: Attrs;
111
+ }
112
+ type Literal = BaseNode<"literal", {
113
+ str: string;
114
+ }>;
115
+ type Sequence = BaseNode<"sequence", {
116
+ nodes: Expr[];
117
+ join?: string;
118
+ }>;
119
+ type Optional = BaseNode<"optional", {
120
+ node: Expr;
121
+ }>;
122
+ type Alternative = BaseNode<"alternative", {
123
+ alts: Expr[];
124
+ }>;
125
+ type Repeat = BaseNode<"repeat", {
126
+ node: Expr;
127
+ join?: string;
128
+ countMin?: number;
129
+ countMax?: number;
130
+ }>;
131
+ type Int = BaseNode<"int", {
132
+ minValue?: number;
133
+ maxValue?: number;
134
+ }>;
135
+ type Float = BaseNode<"float", {
136
+ minValue?: number;
137
+ maxValue?: number;
138
+ }>;
139
+ type Str = BaseNode<"str", Record<string, never>>;
140
+ type Path = BaseNode<"path", {
141
+ resolveParent?: boolean;
142
+ mutable?: boolean;
143
+ mediaTypes?: MediaTypeIdentifier[];
144
+ }>;
145
+ type StructuralNode = Sequence | Optional | Alternative | Repeat;
146
+ type Terminal = Literal | Int | Float | Str | Path;
147
+ type Expr = StructuralNode | Terminal;
148
+ declare function isTerminal(expr: Expr): expr is Terminal;
149
+ declare function isStructural(expr: Expr): expr is StructuralNode;
150
+ //#endregion
151
+ //#region src/ir/builders.d.ts
152
+ declare function lit(str: string): Literal;
153
+ declare function str(meta?: NodeMeta | string): Str;
154
+ declare function int(meta?: NodeMeta | string): Int;
155
+ declare function float(meta?: NodeMeta | string): Float;
156
+ declare function path(meta?: NodeMeta | string): Path;
157
+ declare function seq(...nodes: Expr[]): Sequence;
158
+ declare function seqJoin(join: string, ...nodes: Expr[]): Sequence;
159
+ declare function opt(node: Expr, meta?: NodeMeta | string): Optional;
160
+ declare function rep(node: Expr, meta?: NodeMeta | string): Repeat;
161
+ declare function repJoin(join: string, node: Expr, meta?: NodeMeta | string): Repeat;
162
+ declare function alt(...alts: Expr[]): Alternative;
163
+ //#endregion
164
+ //#region src/ir/format.d.ts
165
+ declare function format(expr: Expr, meta?: AppMeta): string;
166
+ //#endregion
167
+ //#region src/ir/passes/pass.d.ts
168
+ declare enum PassStatus {
169
+ Unchanged = "unchanged",
170
+ Changed = "changed",
171
+ ChangedNeedsRerun = "changed-needs-rerun"
172
+ }
173
+ interface PassResult {
174
+ expr: Expr;
175
+ status: PassStatus;
176
+ warnings?: string[];
177
+ }
178
+ interface Pass {
179
+ readonly name: string;
180
+ apply(expr: Expr): PassResult;
181
+ }
182
+ declare function compose(...passes: Pass[]): Pass;
183
+ declare function fixpoint(pass: Pass, maxIterations?: number): Pass;
184
+ //#endregion
185
+ //#region src/ir/passes/canonicalize.d.ts
186
+ /**
187
+ * Canonicalize IR for consistent representation:
188
+ * - Sort alternatives by kind, then name, then structure
189
+ * - Deduplicate identical alternatives
190
+ */
191
+ declare const canonicalize: Pass;
192
+ //#endregion
193
+ //#region src/ir/passes/flatten.d.ts
194
+ /**
195
+ * Flatten passes
196
+ * - seq(a, seq(b, c)) -> seq(a, b, c)
197
+ * - alt(a, alt(b, c)) -> alt(a, b, c)
198
+ */
199
+ declare const flatten: Pass;
200
+ //#endregion
201
+ //#region src/ir/passes/pipeline.d.ts
202
+ declare const defaultPipeline: Pass;
203
+ declare function createPipeline(passes: Pass[], options?: {
204
+ fixpoint?: boolean;
205
+ maxIterations?: number;
206
+ }): Pass;
207
+ //#endregion
208
+ //#region src/ir/passes/simplify.d.ts
209
+ /**
210
+ * Simplify passes:
211
+ * - optional(optional(T)) -> optional(T)
212
+ * - repeat(repeat(T)) -> repeat(T) with merged constraints
213
+ * - seq(T) -> T, alt(T) -> T (singleton unwrapping)
214
+ * - seq(lit("a"), lit("b")) -> seq(lit("ab")) (merge consecutive literals)
215
+ *
216
+ * Every collapse that drops a wrapper layer merges that layer's `NodeMeta`
217
+ * into the surviving node via `mergeMeta`, so names and attached outputs are
218
+ * never lost.
219
+ */
220
+ declare const simplify: Pass;
221
+ //#endregion
222
+ //#region src/ir/passes/remove-empty.d.ts
223
+ /**
224
+ * Remove empty nodes:
225
+ * - seq() → removed
226
+ * - alt() → removed
227
+ * - opt(seq()) → removed
228
+ * - rep(alt()) → removed
229
+ */
230
+ declare const removeEmpty: Pass;
231
+ //#endregion
232
+ //#region src/frontend/frontend.d.ts
233
+ interface ParseResult {
234
+ meta?: AppMeta;
235
+ expr: Expr;
236
+ errors: ParseError[];
237
+ warnings: ParseWarning[];
238
+ }
239
+ interface ParseError {
240
+ message: string;
241
+ location?: SourceLocation;
242
+ }
243
+ interface ParseWarning {
244
+ message: string;
245
+ location?: SourceLocation;
246
+ }
247
+ interface SourceLocation {
248
+ file?: string;
249
+ line?: number;
250
+ column?: number;
251
+ }
252
+ interface Frontend {
253
+ readonly name: string;
254
+ readonly extensions: string[];
255
+ parse(source: string, filename?: string): ParseResult;
256
+ }
257
+ //#endregion
258
+ //#region src/bindings/resolved-output.d.ts
259
+ /**
260
+ * Resolved token in an output path template. Refs point at solved bindings;
261
+ * literals are emitted verbatim.
262
+ */
263
+ type ResolvedToken = {
264
+ kind: "literal";
265
+ value: string;
266
+ } | {
267
+ kind: "ref";
268
+ binding: BindingId;
269
+ stripExtensions?: string[];
270
+ fallback?: string;
271
+ };
272
+ /**
273
+ * One wrapper layer on a binding's path from the root. Atoms are stored
274
+ * root-to-leaf in `Binding.gate`; backends nest wrappers in array order.
275
+ *
276
+ * - `present`: the binding is inside the active branch of `binding` (a non-null
277
+ * `optional`, `true` for a `bool`, `> 0` for a `count`). Reads as a boolean
278
+ * guard at codegen.
279
+ * - `variant`: the binding is inside the `variant` arm of the union bound by
280
+ * `binding`. Reads as a discriminator check.
281
+ * - `iter`: the binding is inside a `repeat` whose value is a `list`. Reads as
282
+ * a per-element loop variable bound to `binding`.
283
+ */
284
+ type GateAtom = {
285
+ kind: "present";
286
+ binding: BindingId;
287
+ } | {
288
+ kind: "variant";
289
+ binding: BindingId;
290
+ variant: string;
291
+ } | {
292
+ kind: "iter";
293
+ binding: BindingId;
294
+ };
295
+ /**
296
+ * Output specification translated against the binding registry. Pure template
297
+ * data: a name and a token sequence. Per-output gating is derived at codegen
298
+ * time from the declaring scope's gate plus each ref binding's gate.
299
+ */
300
+ interface ResolvedOutput {
301
+ name: string;
302
+ doc?: Documentation;
303
+ tokens: ResolvedToken[];
304
+ mediaTypes?: MediaTypeIdentifier[];
305
+ }
306
+ /**
307
+ * Outputs declared on one struct binding, grouped under that scope. The
308
+ * solver guarantees a binding on every output-carrying sequence (forcing a
309
+ * struct binding even when it would otherwise collapse), so the scope is
310
+ * always a real BindingId. Per-output gating derives from the scope binding's
311
+ * `gate` plus each ref binding's `gate`.
312
+ */
313
+ interface OutputScope {
314
+ scope: BindingId;
315
+ outputs: ResolvedOutput[];
316
+ }
317
+ //#endregion
318
+ //#region src/bindings/types.d.ts
319
+ type BoundType = {
320
+ kind: "scalar";
321
+ scalar: ScalarKind;
322
+ } | {
323
+ kind: "bool";
324
+ } | {
325
+ kind: "count";
326
+ } | {
327
+ kind: "literal";
328
+ value: string | number;
329
+ } | {
330
+ kind: "optional";
331
+ inner: BoundType;
332
+ } | {
333
+ kind: "list";
334
+ item: BoundType;
335
+ } | {
336
+ kind: "struct";
337
+ fields: Record<string, BoundType>;
338
+ } | {
339
+ kind: "union";
340
+ variants: BoundVariant[];
341
+ };
342
+ interface BoundVariant {
343
+ name?: string;
344
+ type: BoundType;
345
+ }
346
+ //#endregion
347
+ //#region src/bindings/binding.d.ts
348
+ type BindingId = string;
349
+ /**
350
+ * One step in a binding's access path relative to top-level `params`.
351
+ *
352
+ * - `field`: descend into a named field of the enclosing struct scope. Renders
353
+ * as `params.name` (TS) / `params["name"]` (Python).
354
+ * - `iter`: the access base resets to the per-element loop variable bound to
355
+ * `binding` (a `repeat`-of-list). The renderer substitutes the active loop
356
+ * variable at emit time (from the `iter` gate atom's loop, or the
357
+ * arg-builder's local loop), so segments after an `iter` build off the
358
+ * element rather than off `params`.
359
+ *
360
+ * There is deliberately no `variant` or `directValue` segment: complex-union
361
+ * variant fields are plain `field` segments off the union's own path (the
362
+ * `@type` discriminant lives in `GateAtom`, not the access path), and the
363
+ * solver's wrapper collapses (`optional<scalar>`, scalar lists) are expressed
364
+ * by a binding simply inheriting its parent wrapper's path.
365
+ */
366
+ type AccessSegment = {
367
+ kind: "field";
368
+ name: string;
369
+ } | {
370
+ kind: "iter";
371
+ binding: BindingId;
372
+ };
373
+ /**
374
+ * A binding's location relative to top-level `params`, as a structured segment
375
+ * sequence. Computed once by the solver (`assignAccessPaths`) and rendered by
376
+ * each backend's `renderAccess`, so the arg-builder and outputs emitter share
377
+ * one source of truth instead of each re-deriving paths.
378
+ */
379
+ type AccessPath = AccessSegment[];
380
+ interface Binding {
381
+ id: BindingId;
382
+ node: Expr;
383
+ name: string;
384
+ type: BoundType;
385
+ /**
386
+ * Wrapper layers on the path from the root to this binding, root-to-leaf.
387
+ * Captures the optional/repeat/alternative ancestors as `present`/`iter`/
388
+ * `variant` atoms. Backends nest wrappers in array order; "is this binding
389
+ * conditionally active?" reduces to `gate.length > 0`.
390
+ */
391
+ gate: GateAtom[];
392
+ /**
393
+ * Access path relative to top-level `params`, assigned by the solver's
394
+ * `assignAccessPaths` pass after types settle. Backends render it via
395
+ * `renderAccess` rather than re-walking the IR to recompute where this
396
+ * binding lives.
397
+ */
398
+ access: AccessPath;
399
+ }
400
+ type BindingRegistry = Map<BindingId, Binding>;
401
+ type OutputDiagnosticLevel = "error" | "warning";
402
+ interface OutputDiagnostic {
403
+ output: string;
404
+ message: string;
405
+ level: OutputDiagnosticLevel;
406
+ }
407
+ interface OutputValidationResult {
408
+ errors: OutputDiagnostic[];
409
+ warnings: OutputDiagnostic[];
410
+ }
411
+ interface SolveResult {
412
+ bindings: BindingRegistry;
413
+ resolve: (node: Expr) => Binding | undefined;
414
+ }
415
+ declare function createRegistry(): BindingRegistry;
416
+ //#endregion
417
+ //#region src/bindings/output-gate.d.ts
418
+ /**
419
+ * The unified wrapper sequence for a single output: the scope's gate, then for
420
+ * each ref token both the ref binding's path-gate and (if its type is itself
421
+ * "thick" - nullable or iterable) a self-atom on the ref binding. Atoms are
422
+ * deduped while preserving first-occurrence order.
423
+ *
424
+ * The self-atom encodes facts derivable from `Binding.type` alone:
425
+ * - `optional`, `bool`, `count` -> `present(binding)` (value may be absent)
426
+ * - `list` -> `iter(binding)` (iterate per element)
427
+ *
428
+ * `scopeGate` is the gate of the scope's struct binding (often `[]` at the
429
+ * root). Backends nest wrappers in array order; the atom kind decides whether
430
+ * it renders as a guard (`present` / `variant`) or a loop (`iter`).
431
+ */
432
+ declare function outputGate(scopeGate: GateAtom[], output: ResolvedOutput, bindings: BindingRegistry): GateAtom[];
433
+ declare function atomKey(atom: GateAtom): string;
434
+ //#endregion
435
+ //#region src/bindings/format.d.ts
436
+ interface FormatExtras {
437
+ scopes?: OutputScope[];
438
+ diagnostics?: OutputValidationResult;
439
+ }
440
+ declare function formatSolveResult(result: SolveResult, expr: Expr, extras?: FormatExtras): string;
441
+ //#endregion
442
+ //#region src/solver/resolve-outputs.d.ts
443
+ interface OutputResolution {
444
+ scopes: OutputScope[];
445
+ diagnostics: OutputValidationResult;
446
+ }
447
+ /**
448
+ * Translate each `NodeMeta.outputs` entry against the binding registry,
449
+ * grouped by the declaring struct binding (the "scope"). The solver forces a
450
+ * binding on every output-carrying sequence, so an output without a scope
451
+ * binding indicates a frontend bug (outputs attached to a non-sequence
452
+ * node) - it is reported as a diagnostic and dropped.
453
+ */
454
+ declare function resolveOutputs(root: Expr, solved: SolveResult): OutputResolution;
455
+ //#endregion
456
+ //#region src/solver/solver.d.ts
457
+ interface SolveOptions {
458
+ namingStrategy?: NamingStrategy;
459
+ }
460
+ interface NamingStrategy {
461
+ getName: (node: Expr, path: string[]) => string;
462
+ generateId: () => BindingId;
463
+ }
464
+ declare function defaultNamingStrategy(): NamingStrategy;
465
+ declare function solve(expr: Expr, options?: SolveOptions): SolveResult;
466
+ //#endregion
467
+ //#region src/manifest/types.d.ts
468
+ interface ProjectMeta {
469
+ name?: string;
470
+ version?: string;
471
+ doc?: Documentation;
472
+ license?: Documentation;
473
+ }
474
+ interface PackageMeta {
475
+ name?: string;
476
+ version?: string;
477
+ docker?: string;
478
+ doc?: Documentation;
479
+ }
480
+ //#endregion
481
+ //#region src/manifest/context.d.ts
482
+ interface CodegenContext {
483
+ expr: Expr;
484
+ bindings: BindingRegistry;
485
+ resolve: SolveResult["resolve"];
486
+ outputScopes: OutputScope[];
487
+ outputDiagnostics: OutputValidationResult;
488
+ app?: AppMeta;
489
+ package?: PackageMeta;
490
+ project?: ProjectMeta;
491
+ }
492
+ declare function createContext(expr: Expr, solveResult: SolveResult, outputs: OutputResolution, meta?: {
493
+ app?: AppMeta;
494
+ package?: PackageMeta;
495
+ project?: ProjectMeta;
496
+ }): CodegenContext;
497
+ //#endregion
498
+ //#region src/backend/scope.d.ts
499
+ /** Symbol collision avoidance for code generation. */
500
+ declare class Scope {
501
+ private readonly reserved;
502
+ private readonly used;
503
+ private readonly parent?;
504
+ constructor(reserved?: Iterable<string>, parent?: Scope);
505
+ /** Check if a symbol is already taken (in this scope or any parent). */
506
+ has(symbol: string): boolean;
507
+ /**
508
+ * Add a symbol, appending a numeric suffix to avoid collisions. Returns the
509
+ * safe name.
510
+ *
511
+ * When a `recase` transform is given, a disambiguated candidate is routed back
512
+ * through it so the suffix is absorbed into the identifier's casing - e.g.
513
+ * `pascalCase` folds `Config_2` into `Config2` - rather than leaving a
514
+ * mixed-case `Config_2`. Uniqueness is always checked on the final emitted
515
+ * form, so two hints that case-collide still get distinct names. Defaults to
516
+ * identity (the bare `<name>_<n>` suffix) for callers that don't case-normalize.
517
+ */
518
+ add(candidate: string, recase?: (s: string) => string): string;
519
+ /** Create a child scope that inherits this scope's restrictions. */
520
+ child(reserved?: Iterable<string>): Scope;
521
+ }
522
+ //#endregion
523
+ //#region src/backend/backend.d.ts
524
+ interface EmitResult {
525
+ files: Map<string, string>;
526
+ errors: EmitError[];
527
+ warnings: EmitWarning[];
528
+ }
529
+ interface EmitError {
530
+ message: string;
531
+ }
532
+ interface EmitWarning {
533
+ message: string;
534
+ }
535
+ /**
536
+ * What the suite-level dispatcher needs to route a config object to one app's
537
+ * dict-style executor, keyed by the root `@type` discriminator.
538
+ */
539
+ interface AppEntrypoint {
540
+ /** Root `@type` discriminator value (`<package>/<app>`). */
541
+ type: string;
542
+ /**
543
+ * Dict-style execute function name - `<tool>Execute` / `<tool>_execute` for a
544
+ * struct root, `<tool>` for a non-struct root. Takes `(params, runner)`.
545
+ */
546
+ executeFn: string;
547
+ }
548
+ interface EmittedApp extends EmitResult {
549
+ meta?: AppMeta;
550
+ /**
551
+ * Dispatch entrypoint, present when the app has a stable `@type` (both an id
552
+ * and a package name are known). Consumed by `emitPackage` to build the
553
+ * suite-level `execute(params, runner)` dispatcher.
554
+ */
555
+ entrypoint?: AppEntrypoint;
556
+ }
557
+ interface EmittedPackage extends EmitResult {
558
+ meta?: PackageMeta;
559
+ }
560
+ /**
561
+ * A code generator for one target language. Implementations emit in up to
562
+ * three tiers; only `emitApp` is mandatory.
563
+ *
564
+ * The CLI's `--mode` flag selects which tiers run: `scripts` = `emitApp` only,
565
+ * `single` = `emitApp` + one `emitPackage`, `multi` = all three tiers.
566
+ *
567
+ * Paths in returned file maps are relative to the emit tier's natural root
568
+ * (package directory for app/package emit, project root for project emit).
569
+ * Orchestration is responsible for prefixing/merging the maps.
570
+ */
571
+ interface Backend {
572
+ readonly name: string;
573
+ readonly target: string;
574
+ /**
575
+ * Emit the per-tool file(s) for one app. Mandatory.
576
+ *
577
+ * When emitting many tools into one suite barrel, pass a `scope` shared across
578
+ * the package (from `newPackageScope`) so emitted top-level names stay unique
579
+ * across tools - a flat `export *` / `from .x import *` re-export otherwise
580
+ * collides same-named types. Omit it for standalone single-tool emission.
581
+ */
582
+ emitApp(ctx: CodegenContext, scope?: Scope): EmittedApp;
583
+ /**
584
+ * Create a fresh symbol scope seeded with this backend's reserved words, to be
585
+ * shared across all `emitApp` calls for one package. Optional; callers fall
586
+ * back to per-tool scoping (still safe via name prefixing) when absent.
587
+ */
588
+ newPackageScope?(): Scope;
589
+ /**
590
+ * Emit suite-level files for a package containing many apps (e.g. the
591
+ * `__init__.py` re-exporting `from .bet import *` per tool, or an
592
+ * `index.ts` doing `export * from "./bet.js"`). Optional; defaulted to
593
+ * no-op by callers when absent.
594
+ */
595
+ emitPackage?(pkg: PackageMeta, apps: EmittedApp[]): EmittedPackage;
596
+ /**
597
+ * Emit project-level artifacts spanning many packages (e.g. root
598
+ * `pyproject.toml`, top-level `__init__.py`, runner helpers).
599
+ * Wired up by Plan 2's CLI catalog mode; backends opt in as needed.
600
+ */
601
+ emitProject?(proj: ProjectMeta, packages: EmittedPackage[]): EmitResult;
602
+ }
603
+ interface TypeMap {
604
+ map(type: BoundType): string;
605
+ imports(type: BoundType): string[];
606
+ }
607
+ //#endregion
608
+ //#region src/backend/boutiques/boutiques.d.ts
609
+ interface BtDescriptor {
610
+ name?: string;
611
+ id?: string;
612
+ description?: string;
613
+ "schema-version"?: string;
614
+ "tool-version"?: string;
615
+ author?: string;
616
+ url?: string;
617
+ "container-image"?: {
618
+ image: string;
619
+ type?: string;
620
+ };
621
+ "command-line"?: string;
622
+ inputs?: BtInput[];
623
+ "stdout-output"?: {
624
+ id: string;
625
+ name?: string;
626
+ description?: string;
627
+ };
628
+ "stderr-output"?: {
629
+ id: string;
630
+ name?: string;
631
+ description?: string;
632
+ };
633
+ "output-files"?: BtOutputFile[];
634
+ }
635
+ interface BtOutputFile {
636
+ id: string;
637
+ name?: string;
638
+ description?: string;
639
+ "path-template": string;
640
+ optional?: boolean;
641
+ list?: boolean;
642
+ "path-template-stripped-extensions"?: string[];
643
+ }
644
+ interface BtInput {
645
+ id: string;
646
+ name?: string;
647
+ description?: string;
648
+ type: string | BtDescriptor | BtDescriptor[];
649
+ "value-key": string;
650
+ optional?: boolean;
651
+ list?: boolean;
652
+ "list-separator"?: string;
653
+ "min-list-entries"?: number;
654
+ "max-list-entries"?: number;
655
+ "command-line-flag"?: string;
656
+ "command-line-flag-separator"?: string;
657
+ "value-choices"?: (string | number)[];
658
+ "default-value"?: string | number | boolean;
659
+ minimum?: number;
660
+ maximum?: number;
661
+ integer?: boolean;
662
+ "resolve-parent"?: boolean;
663
+ mutable?: boolean;
664
+ }
665
+ declare function generateBoutiques(ctx: CodegenContext): {
666
+ descriptor: BtDescriptor;
667
+ warnings: EmitWarning[];
668
+ };
669
+ declare class BoutiquesBackend implements Backend {
670
+ readonly name = "boutiques";
671
+ readonly target = "boutiques";
672
+ emitApp(ctx: CodegenContext): EmittedApp;
673
+ }
674
+ //#endregion
675
+ //#region src/backend/code-builder.d.ts
676
+ /** Line-buffer abstraction for code emission. */
677
+ declare class CodeBuilder {
678
+ private readonly lines;
679
+ private depth;
680
+ private readonly indentStr;
681
+ constructor(indent?: string);
682
+ /** Append a line at the current indentation level. */
683
+ line(text: string): this;
684
+ /** Append a blank line. */
685
+ blank(): this;
686
+ /** Append a comment line. */
687
+ comment(text: string, prefix?: string): this;
688
+ /** Run a callback with increased indentation. */
689
+ indent(fn: () => void): this;
690
+ /** Append all lines from another CodeBuilder at the current indentation level. */
691
+ append(other: CodeBuilder): this;
692
+ /** Return the built code as a string. */
693
+ toString(): string;
694
+ }
695
+ //#endregion
696
+ //#region src/backend/collect-field-info.d.ts
697
+ /**
698
+ * Metadata extracted for each field of a struct type.
699
+ *
700
+ * `doc` is the field's description, recovered from wrapper nodes via `findDoc`.
701
+ * `defaultValue` is pulled from the wrapper or binding node's metadata.
702
+ */
703
+ interface FieldInfo {
704
+ doc?: string;
705
+ defaultValue?: string | number | boolean;
706
+ }
707
+ /**
708
+ * Collect field metadata (doc, defaultValue) for each field of a struct type.
709
+ *
710
+ * Walks the IR tree to find the sequence node containing the struct's fields,
711
+ * then resolves each child to its field binding. Metadata is recovered from both
712
+ * the wrapper node (where the parser hoists doc) and the binding node (where the
713
+ * solver places the binding after sequence collapse).
714
+ */
715
+ declare function collectFieldInfo(ctx: CodegenContext, structType: Extract<BoundType, {
716
+ kind: "struct";
717
+ }>): Map<string, FieldInfo>;
718
+ //#endregion
719
+ //#region src/backend/collect-named-types.d.ts
720
+ /** A named compound type (struct or union) discovered during type collection. */
721
+ interface NamedType {
722
+ name: string;
723
+ type: BoundType;
724
+ }
725
+ /**
726
+ * Recursively collect all struct/union types and assign unique names.
727
+ *
728
+ * Walks the BoundType tree depth-first, using structural keys (`structKey`,
729
+ * `unionKey`) to deduplicate types that appear multiple times in the tree.
730
+ * Each unique struct/union gets a name generated by applying `nameTransform`
731
+ * to a hint string (derived from the root name or field/variant names).
732
+ *
733
+ * @param rootType - The root BoundType to walk.
734
+ * @param rootName - The hint for the root type's name (already tool-qualified).
735
+ * @param scope - Symbol scope for collision avoidance.
736
+ * @param nameTransform - Converts a hint string to a type name (e.g. pascalCase, snake_case).
737
+ * @param nestedPrefix - Prepended to every NON-root type name so a suite's flat
738
+ * barrel (`export * from`/`from .x import *`) can't collide two tools' types
739
+ * that share a local field/variant name (e.g. `Outputtype`). Pass the tool's
740
+ * type prefix (its root name); defaults to "" for single-tool emission.
741
+ * @returns `namedTypes` maps structural keys to assigned names, `typeDecls` lists declarations in order.
742
+ */
743
+ declare function collectNamedTypes(rootType: BoundType, rootName: string, scope: Scope, nameTransform: (hint: string) => string, nestedPrefix?: string): {
744
+ namedTypes: Map<string, string>;
745
+ typeDecls: NamedType[];
746
+ };
747
+ /**
748
+ * Create a type name resolver from a namedTypes map.
749
+ * Returns a function that maps a BoundType to its assigned name (if any).
750
+ */
751
+ declare function resolveTypeName(namedTypes: Map<string, string>): (type: BoundType) => string | undefined;
752
+ //#endregion
753
+ //#region src/backend/find-doc.d.ts
754
+ /**
755
+ * Find a description from an IR node, traversing through wrapper nodes.
756
+ *
757
+ * The parser's `wrapNode` hoists doc metadata to the outermost wrapper node,
758
+ * but the solver's simplify pass can collapse sequences, burying descriptions
759
+ * deeper in the tree.
760
+ *
761
+ * This traversal is type-aware: it only enters sequences when the corresponding
762
+ * BoundType is not a struct. Struct sequences have their own field collection
763
+ * call, so entering them would steal nested struct children's descriptions.
764
+ *
765
+ * @param node - The IR node to search for a description.
766
+ * @param fieldType - The BoundType of the field, used to determine traversal boundaries.
767
+ */
768
+ declare function findDoc(node: Expr, fieldType: BoundType): string | undefined;
769
+ //#endregion
770
+ //#region src/backend/find-struct-node.d.ts
771
+ /**
772
+ * Find the sequence node whose child bindings match a struct type's fields.
773
+ *
774
+ * Traverses through optional, repeat, and alternative wrappers to find the
775
+ * sequence that directly contains the struct's field bindings. This is necessary
776
+ * because the solver may collapse `seq(lit("--flag"), terminal)` into the terminal,
777
+ * burying bindings deeper in the tree.
778
+ *
779
+ * Uses a two-phase check for sequences:
780
+ * 1. Direct binding check (`ctx.resolve`) - matches when bindings are on immediate children
781
+ * 2. Recursive binding check (`resolveFieldBinding`) - matches when solver collapsed
782
+ * a seq(lit, terminal) and the binding is buried deeper
783
+ *
784
+ * Phase 1 is tried first to avoid falsely matching an outer sequence when an inner
785
+ * sequence is the actual struct owner (e.g. `seq(lit("--flag"), seq(field1, field2))`).
786
+ */
787
+ declare function findStructNode(node: Expr, ctx: CodegenContext, structType: Extract<BoundType, {
788
+ kind: "struct";
789
+ }>): Extract<Expr, {
790
+ kind: "sequence";
791
+ }> | undefined;
792
+ //#endregion
793
+ //#region src/backend/resolve-field-binding.d.ts
794
+ /**
795
+ * Resolve a struct child node to its field binding, handling collapsed sequences.
796
+ *
797
+ * When the solver's simplify pass collapses `seq(lit("--flag"), terminal)` into
798
+ * just the terminal, the binding ends up on the inner node while metadata (doc,
799
+ * defaultValue) may remain on the outermost wrapper. This function recursively
800
+ * descends through collapsed sequences to find the binding, tracking the outermost
801
+ * node for metadata recovery.
802
+ *
803
+ * Uses type identity (`===`) to verify the binding matches the struct's field type,
804
+ * preventing cross-nesting name collisions where an inner struct has a field with
805
+ * the same name as the outer struct.
806
+ */
807
+ declare function resolveFieldBinding(node: Expr, ctx: CodegenContext, structType: Extract<BoundType, {
808
+ kind: "struct";
809
+ }>, outermost?: Expr): {
810
+ binding: Binding;
811
+ wrapperNode: Expr;
812
+ } | undefined;
813
+ //#endregion
814
+ //#region src/backend/resolve-output-tokens.d.ts
815
+ /**
816
+ * Compact consecutive literal tokens. Backends that emit string concatenation
817
+ * benefit from a shorter token stream; backends that template each token
818
+ * individually can ignore this and use `output.tokens` directly.
819
+ */
820
+ declare function compactTokens(tokens: ResolvedToken[]): ResolvedToken[];
821
+ /**
822
+ * One output ready for codegen. `gate` is the wrapper sequence (outermost
823
+ * first); the backend renders each atom as the appropriate scope-introducing
824
+ * statement, then emits the path expression inside the innermost layer.
825
+ */
826
+ interface OutputEmitPlan {
827
+ name: string;
828
+ gate: GateAtom[];
829
+ tokens: ResolvedToken[];
830
+ resolved: ResolvedOutput;
831
+ }
832
+ declare function planOutput(scopeGate: GateAtom[], output: ResolvedOutput, bindings: BindingRegistry): OutputEmitPlan;
833
+ /**
834
+ * Does the output have any conditional wrapper? Equivalent to "is at least one
835
+ * atom a `present` or `variant`?". `iter` alone means the output emits a list
836
+ * and is not conditionally absent.
837
+ */
838
+ declare function isGated(plan: OutputEmitPlan): boolean;
839
+ /** Does the output iterate (emit zero-or-more values)? */
840
+ declare function isIterated(plan: OutputEmitPlan): boolean;
841
+ /**
842
+ * Convenience for backends emitting all outputs of a scope at once. The caller
843
+ * provides the scope's gate (typically `bindings.get(scope.scope)?.gate ?? []`).
844
+ */
845
+ declare function planScope(scope: OutputScope, scopeGate: GateAtom[], bindings: BindingRegistry): OutputEmitPlan[];
846
+ //#endregion
847
+ //#region src/backend/sig-entries.d.ts
848
+ /**
849
+ * One entry of a kwarg-style signature, shared across language backends. Each
850
+ * entry describes a single user-facing parameter of the `_params()` factory
851
+ * and the kwarg wrapper:
852
+ * - `sigType`/`sigDefault` go directly into the function signature
853
+ * - `isOptional`/`hasExplicitDefault` drive the dict-build branches (required
854
+ * and explicitly-defaulted fields are always set; optional-no-default fields
855
+ * are conditionally set when not None/null)
856
+ * - `doc` is rendered into the per-param doc block (Args / @param)
857
+ *
858
+ * `name` is the scrubbed host identifier (used in the signature and function
859
+ * body); `wireKey` is the Boutiques field name (used as the dict key /
860
+ * TypedDict field key). They diverge when the wire key collides with a host
861
+ * reserved word, is not a valid identifier, or shadows a local in the emitting
862
+ * function (e.g. wire `float` -> host `float_`, wire `4d_input` -> host
863
+ * `v_4d_input`).
864
+ */
865
+ interface SigEntry {
866
+ /** Scrubbed host identifier - safe to use in signatures and as a local. */
867
+ name: string;
868
+ /** Boutiques field name - used as the dict key / TypedDict field key. */
869
+ wireKey: string;
870
+ sigType: string;
871
+ /** Rendered default expression in the host language, or undefined for required-no-default. */
872
+ sigDefault?: string;
873
+ /** True iff the BoundType is `optional` (i.e. dict-build conditionally includes). */
874
+ isOptional: boolean;
875
+ /** True iff the field carries an explicit defaultValue in its FieldInfo. */
876
+ hasExplicitDefault: boolean;
877
+ doc?: string;
878
+ }
879
+ /** Per-backend rendering hooks for `buildSigEntries`. */
880
+ interface SigOptions {
881
+ /** Render a non-optional BoundType as a language-native type expression. */
882
+ renderType: (t: BoundType) => string;
883
+ /** Suffix appended to `renderType(inner)` for optional fields (e.g. ` | None`, ` | null`). */
884
+ nullableSuffix: string;
885
+ /** Default expression for optional-no-default fields (e.g. `None`, `null`). */
886
+ nullableDefault: string;
887
+ /** Render a JS scalar default as a host-language literal (e.g. `True`/`true`). */
888
+ renderDefault: (v: string | number | boolean) => string;
889
+ }
890
+ /**
891
+ * Build per-field signature entries for the kwarg wrapper and params factory.
892
+ * Skips `@type` (the factory injects it as a constant). Required-no-default
893
+ * entries are placed before defaulted ones so the resulting signature is
894
+ * syntactically valid in both Python and TS.
895
+ *
896
+ * `registerLocal` is called once per field with the wire key; it must return
897
+ * a scrubbed, unique host identifier (typically by combining a language-aware
898
+ * scrub function with `Scope.add()`). The caller's scope should already have
899
+ * the function's other locals (`params`, `runner`, ...) reserved so this
900
+ * registration cannot collide with them.
901
+ */
902
+ declare function buildSigEntries(rootType: Extract<BoundType, {
903
+ kind: "struct";
904
+ }>, fieldInfo: Map<string, FieldInfo>, registerLocal: (wireKey: string) => string, opts: SigOptions): SigEntry[];
905
+ //#endregion
906
+ //#region src/backend/type-keys.d.ts
907
+ /**
908
+ * Stable, fully structural identity key for any BoundType.
909
+ *
910
+ * Two types share a key iff they are structurally identical - same shape AND
911
+ * same leaf types/literal values, recursively. This is what `collectNamedTypes`
912
+ * dedups on: distinct nominal types must get distinct keys so each gets its own
913
+ * generated name.
914
+ *
915
+ * Keying on field/variant *names* alone is too coarse: discriminated-union
916
+ * variants that differ only by their `@type` literal (e.g. ANTs' `transform_*`
917
+ * variants, all `{ "@type": <literal>, gradient_step: float }`) would collapse
918
+ * to one identity, emitting `Transform = TransformRigid | TransformRigid | ...`
919
+ * and breaking discriminated-union narrowing. Including the field types (and
920
+ * thus the `@type` literal value) keeps them distinct.
921
+ */
922
+ declare function typeKey(type: BoundType): string;
923
+ /** Stable identity key for a struct type (field names + field types). */
924
+ declare function structKey(type: Extract<BoundType, {
925
+ kind: "struct";
926
+ }>): string;
927
+ /** Stable identity key for a union type (variant names + variant types). */
928
+ declare function unionKey(type: Extract<BoundType, {
929
+ kind: "union";
930
+ }>): string;
931
+ //#endregion
932
+ //#region src/backend/python/python.d.ts
933
+ declare function generatePython(ctx: CodegenContext, packageScope?: Scope): string;
934
+ declare class PythonBackend implements Backend {
935
+ readonly name = "python";
936
+ readonly target = "python";
937
+ emitApp(ctx: CodegenContext, scope?: Scope): EmittedApp;
938
+ newPackageScope(): Scope;
939
+ emitPackage(pkg: PackageMeta, apps: EmittedApp[]): EmittedPackage;
940
+ emitProject(proj: ProjectMeta, packages: EmittedPackage[]): EmitResult;
941
+ }
942
+ //#endregion
943
+ //#region src/backend/snippet-core.d.ts
944
+ /**
945
+ * Per-language rendering hooks for the call-site snippet renderer. The recursive
946
+ * structure (struct -> object literal, union -> picked variant, list -> array)
947
+ * is language-agnostic; only leaf-literal syntax, object keys, and indentation
948
+ * differ, and those are supplied here.
949
+ */
950
+ interface SnippetDialect {
951
+ /** One indentation level (e.g. `" "` for Python, `" "` for TypeScript). */
952
+ indentUnit: string;
953
+ /** Render a string value as a host literal (quoted). */
954
+ string(value: string): string;
955
+ /** Render a boolean value as a host literal (`True`/`true`). */
956
+ boolean(value: boolean): string;
957
+ /** Render a number value as a host literal. */
958
+ number(value: number): string;
959
+ /** Host literal for a null/None value. */
960
+ null: string;
961
+ /** Render an object-literal key from a wire key, quoting when not a bare identifier. */
962
+ objKey(wireKey: string): string;
963
+ }
964
+ /** Options shared by both language renderers. */
965
+ interface SnippetOptions {
966
+ /**
967
+ * Module the package is imported from (e.g. `"niwrap"`). Defaults to the
968
+ * project name on the context. When unset and no project name is available,
969
+ * Python falls back to a bare `import <pkg>` and TypeScript omits the import.
970
+ */
971
+ packageRoot?: string;
972
+ /** Whether to prepend an import line. Defaults to `true`. */
973
+ includeImport?: boolean;
974
+ }
975
+ /**
976
+ * Render a struct config as a host object literal (Python dict / TS object).
977
+ * Keys are the Boutiques wire names (the generated TypedDict / interface keys) -
978
+ * nested structs have no constructor function in the generated code, so callers
979
+ * build them as plain object literals.
980
+ *
981
+ * `@type` is emitted from the struct's literal discriminator field when present
982
+ * (union variants carry a required, load-bearing `@type`); for the root call the
983
+ * tag is injected via `injectAtType` (the root's `@type` is derived from
984
+ * `pkg/appId`, not stored as a field). Non-`@type` literal fields have no
985
+ * runtime representation and are skipped.
986
+ */
987
+ declare function renderStructLiteral(value: unknown, type: Extract<BoundType, {
988
+ kind: "struct";
989
+ }>, indent: string, d: SnippetDialect, injectAtType?: string): string;
990
+ /**
991
+ * Render a config value to a host-language expression, guided by its BoundType.
992
+ *
993
+ * `indent` is the leading whitespace of the line the value starts on; multi-line
994
+ * forms (object/array literals) place their members one level deeper and close
995
+ * back at `indent`. The renderer follows the BoundType tree for shape and reads
996
+ * the parallel config object for values, so unknown / absent keys are simply
997
+ * omitted (a partial config produces a partial snippet).
998
+ */
999
+ declare function renderValue(value: unknown, type: BoundType, indent: string, d: SnippetDialect): string;
1000
+ //#endregion
1001
+ //#region src/backend/python/snippet.d.ts
1002
+ /**
1003
+ * Render a Python call snippet for one tool from a config object (the params
1004
+ * dict the form produces, keyed by Boutiques wire names).
1005
+ *
1006
+ * Struct-rooted tools use the ergonomic kwarg wrapper -
1007
+ * `fsl.bet(infile=..., fractional_intensity=0.5)` - whose keyword names are the
1008
+ * *scrubbed host* identifiers (`float` -> `float_`), not the wire keys; the
1009
+ * per-field mapping comes from the same `buildSigEntries` the generated wrapper
1010
+ * is built from, so the snippet matches the real signature. Nested structs /
1011
+ * union variants / lists-of-structs have no constructor in the generated code,
1012
+ * so they render as plain dict literals keyed by wire names.
1013
+ *
1014
+ * Union- (or otherwise non-struct-) rooted tools have no kwarg wrapper; the
1015
+ * single dict-style `<tool>` entry is called with one object-literal argument.
1016
+ *
1017
+ * The snippet matches the *standalone* (single-descriptor) emission of the same
1018
+ * context - which is how the hub compiles - not a catalog emission where a
1019
+ * shared package scope could suffix-bump a name.
1020
+ *
1021
+ * @param ctx - The compiled context (compile -> pipeline -> solve ->
1022
+ * resolveOutputs -> createContext, as in the CLI's `readAndCompile`).
1023
+ * @param config - The params object, keyed by Boutiques *wire* names (not host
1024
+ * identifiers). Every union-typed value - including the root of a union-rooted
1025
+ * tool - must carry its `@type` discriminator so the variant can be matched;
1026
+ * the root struct's `@type` is supplied by the renderer, so omit it there.
1027
+ * @param opts - Import and package-root options.
1028
+ */
1029
+ declare function renderPythonCall(ctx: CodegenContext, config: Record<string, unknown>, opts?: SnippetOptions): string;
1030
+ //#endregion
1031
+ //#region src/backend/schema/jsonschema.d.ts
1032
+ interface JsonSchema {
1033
+ type?: string | string[];
1034
+ items?: JsonSchema;
1035
+ properties?: Record<string, JsonSchema>;
1036
+ required?: string[];
1037
+ oneOf?: JsonSchema[];
1038
+ enum?: (string | number)[];
1039
+ const?: string | number;
1040
+ [key: string]: unknown;
1041
+ }
1042
+ declare function generateSchema(ctx: CodegenContext): JsonSchema;
1043
+ /**
1044
+ * JSON Schema for a tool's **Outputs object**: the set of files it produces
1045
+ * (resolved outputs + mutable inputs surfaced as outputs) plus its captured
1046
+ * stdout/stderr streams. Built from the same `collectOutputFields` /
1047
+ * `streamFields` source of truth the Python and TypeScript backends use to type
1048
+ * the Outputs dataclass/interface, so the three describe the same shape.
1049
+ *
1050
+ * Field encoding (mirrors how the language backends type each field):
1051
+ * - required single -> `{ type: "string", x-styx-type: "path" }`
1052
+ * - optional single -> `{ type: ["string", "null"], x-styx-type: "path" }`
1053
+ * - list output -> `{ type: "array", items: { type: "string", x-styx-type: "path" } }`
1054
+ * - stream field -> `{ type: "array", items: { type: "string" } }` (lines of
1055
+ * text, NOT paths - the absent `x-styx-type` lets a consumer tell them apart)
1056
+ *
1057
+ * EVERY field is `required`: unlike the inputs schema (where an optional param
1058
+ * key is genuinely omitted, so "not in `required`" is faithful), an Outputs
1059
+ * field is always present - a gated single is `null`, a gated list is an empty
1060
+ * array. So optionality is carried by the `null` type branch, and a strict
1061
+ * validator accepts the actual emitted object (e.g. `{ "out_file": null }`).
1062
+ */
1063
+ declare function generateOutputsSchema(ctx: CodegenContext): JsonSchema;
1064
+ declare class JsonSchemaBackend implements Backend {
1065
+ readonly name = "json-schema";
1066
+ readonly target = "json-schema";
1067
+ /** One scope per package so per-tool schema file stems stay unique in the suite directory. */
1068
+ newPackageScope(): Scope;
1069
+ emitApp(ctx: CodegenContext, scope?: Scope): EmittedApp;
1070
+ }
1071
+ //#endregion
1072
+ //#region src/backend/string-case.d.ts
1073
+ declare function snakeCase(s: string): string;
1074
+ declare function screamingSnakeCase(s: string): string;
1075
+ declare function pascalCase(s: string): string;
1076
+ declare function camelCase(s: string): string;
1077
+ //#endregion
1078
+ //#region src/backend/styxdefs-compat.d.ts
1079
+ /**
1080
+ * Runtime version floors baked into generated dependency metadata.
1081
+ *
1082
+ * styx2-generated code calls `mutable_copy` / `mutableCopy` (introduced in the
1083
+ * styxdefs 0.7.0 / styxdefs-js 0.2.0 release), so emitted packages genuinely
1084
+ * require that runtime floor. This is the single source of truth: bump here and
1085
+ * both the Python and TypeScript backends pick it up.
1086
+ */
1087
+ declare const STYXDEFS_COMPAT: {
1088
+ /** PEP 508 specifier for the Python `styxdefs` package. */readonly python: ">=0.7.0,<0.8.0"; /** npm semver range for the `styxdefs` package. */
1089
+ readonly npm: "^0.2.0";
1090
+ };
1091
+ /**
1092
+ * Extra Python runtime packages the root distribution pulls in (container +
1093
+ * graph runners). Left unpinned - styxdefs's floor constrains them transitively
1094
+ * via their own inter-package pins.
1095
+ */
1096
+ declare const PYTHON_RUNNER_DEPS: readonly ["styxdocker", "styxsingularity", "styxgraph"];
1097
+ //#endregion
1098
+ //#region src/backend/typescript/typescript.d.ts
1099
+ declare function generateTypeScript(ctx: CodegenContext, packageScope?: Scope): string;
1100
+ declare class TypeScriptBackend implements Backend {
1101
+ readonly name = "typescript";
1102
+ readonly target = "typescript";
1103
+ emitApp(ctx: CodegenContext, scope?: Scope): EmittedApp;
1104
+ newPackageScope(): Scope;
1105
+ emitPackage(pkg: PackageMeta, apps: EmittedApp[]): EmittedPackage;
1106
+ emitProject(proj: ProjectMeta, packages: EmittedPackage[]): EmitResult;
1107
+ }
1108
+ //#endregion
1109
+ //#region src/backend/typescript/snippet.d.ts
1110
+ /**
1111
+ * Render a TypeScript call snippet for one tool from a config object (keyed by
1112
+ * Boutiques wire names).
1113
+ *
1114
+ * The generated v2 kwarg wrapper takes *positional* arguments, which can't skip
1115
+ * a middle optional - so the runnable object-style entry is the dict-style
1116
+ * `<tool>Execute(params)` (struct roots). The snippet builds the params object
1117
+ * literal (wire-keyed, with the root `@type` injected) and passes it there.
1118
+ * Union- (or otherwise non-struct-) rooted tools call the dict-style `<tool>`
1119
+ * entry the same way. Nested structs / union variants / lists-of-structs have no
1120
+ * constructor in the generated code and render as object literals.
1121
+ *
1122
+ * The snippet matches the *standalone* (single-descriptor) emission of the same
1123
+ * context - which is how the hub compiles - not a catalog emission where a
1124
+ * shared package scope could suffix-bump a name.
1125
+ *
1126
+ * @param ctx - The compiled context (compile -> pipeline -> solve ->
1127
+ * resolveOutputs -> createContext, as in the CLI's `readAndCompile`).
1128
+ * @param config - The params object, keyed by Boutiques *wire* names. Every
1129
+ * union-typed value - including the root of a union-rooted tool - must carry
1130
+ * its `@type` discriminator so the variant can be matched; the root struct's
1131
+ * `@type` is supplied by the renderer, so omit it there.
1132
+ * @param opts - Import and package-root options.
1133
+ */
1134
+ declare function renderTypeScriptCall(ctx: CodegenContext, config: Record<string, unknown>, opts?: SnippetOptions): string;
1135
+ //#endregion
1136
+ //#region src/index.d.ts
1137
+ declare function compile(source: string, filenameOrOptions?: string | {
1138
+ format?: FormatName;
1139
+ filename?: string;
1140
+ }): ParseResult;
1141
+ //#endregion
1142
+ export { AccessPath, AccessSegment, Alternative, AppMeta, Backend, Binding, BindingId, BindingRegistry, BoundType, BoundVariant, BoutiquesBackend, CodeBuilder, CodegenContext, Documentation, EmitError, EmitResult, EmitWarning, EmittedApp, EmittedPackage, Expr, FieldInfo, Float, FormatName, Frontend, GateAtom, Int, JsonSchema, JsonSchemaBackend, Literal, MediaTypeIdentifier, NamedType, NamingStrategy, NodeMeta, NodeRef, Optional, Output, OutputDiagnostic, OutputDiagnosticLevel, OutputEmitPlan, OutputResolution, OutputScope, OutputToken, OutputValidationResult, PYTHON_RUNNER_DEPS, PackageMeta, ParseError, ParseResult, ParseWarning, Pass, PassResult, PassStatus, Path, ProjectMeta, PythonBackend, Repeat, ResolvedOutput, ResolvedToken, STYXDEFS_COMPAT, ScalarKind, Scope, Sequence, SigEntry, SigOptions, SnippetDialect, SnippetOptions, SolveOptions, SolveResult, SourceLocation, Str, StreamOutput, StructuralNode, Terminal, TypeMap, TypeScriptBackend, alt, atomKey, buildSigEntries, camelCase, canonicalize, collectFieldInfo, collectNamedTypes, compactTokens, compile, compose, createContext, createPipeline, createRegistry, defaultNamingStrategy, defaultPipeline, detectFormat, effectiveOutputName, findDoc, findStructNode, fixpoint, flatten, float, format, formatSolveResult, generateBoutiques, generateOutputsSchema, generatePython, generateSchema, generateTypeScript, int, isGated, isIterated, isStructural, isTerminal, lit, nodeRef, opt, outputGate, pascalCase, path, planOutput, planScope, removeEmpty, renderPythonCall, renderStructLiteral, renderTypeScriptCall, renderValue, rep, repJoin, resolveFieldBinding, resolveOutputs, resolveTypeName, screamingSnakeCase, seq, seqJoin, simplify, snakeCase, solve, str, structKey, typeKey, unionKey };
1143
+ //# sourceMappingURL=index.d.mts.map