@sous-io/plugin-api 0.0.0-stage → 1.0.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.
@@ -0,0 +1,151 @@
1
+ import type { Context } from "./context.js";
2
+ import type { Prompter } from "./prompter.js";
3
+ import type { IntentInput, IntentReturn, SousIntents } from "./registry.js";
4
+ import type { Reporter } from "./reporter.js";
5
+ import type { InferOutput, SousSchema } from "./schema.js";
6
+ /** A handler: runs an intent and returns its outputs (see S1, "What an intent returns"). */
7
+ export type IntentHandler<In = any, Result = unknown> = (input: In, ctx: Context) => Result | Promise<Result>;
8
+ /**
9
+ * A wrapper changes what an intent's handler does. Wrappers stack in plugin order: the wrapper of
10
+ * the plugin loaded last runs first and calls `next`, down to the handler.
11
+ *
12
+ * ```ts
13
+ * sous.intents.wrap("build", (next) => async (input, ctx) => {
14
+ * const outputs = await next(input, ctx);
15
+ *
16
+ * return outputs.with(new IntentOutput({ title: "Diagrams", result: await renderDiagrams(ctx) }));
17
+ * });
18
+ * ```
19
+ */
20
+ export type IntentWrapper<In = any, Result = unknown> = (next: IntentHandler<In, Result>) => IntentHandler<In, Result>;
21
+ /** How the CLI shows an intent. */
22
+ export interface CliSection {
23
+ /** The command words. Default: the intent's name split at dots (`namespace.list` → `namespace list`). */
24
+ command?: readonly string[];
25
+ /** More command words that run it, in any group (`["ns", "list"]`, `["list", "namespaces"]`). */
26
+ aliases?: ReadonlyArray<readonly string[]>;
27
+ /** Input fields given as positional arguments, in order. The last may be an array, taking the rest. */
28
+ positional?: readonly string[];
29
+ /**
30
+ * Hands every token the command does not know (unknown flags, extra arguments, everything after
31
+ * `--`) to its last positional, in the order typed, instead of failing: `sous launch claude
32
+ * --resume -- -c` gives `tool: ["claude", "--resume", "-c"]`. The last positional must be an array.
33
+ */
34
+ passThrough?: boolean;
35
+ /** Example command lines for `--help`. */
36
+ examples?: readonly string[];
37
+ /** Keeps it out of help and suggestions; it still runs. */
38
+ hidden?: boolean;
39
+ /** Per input field: a one-letter short flag (`y` for `-y`), more flag names, or hiding it from help. */
40
+ flags?: Readonly<Record<string, CliFlagOptions>>;
41
+ }
42
+ /** CLI options for one input field. */
43
+ export interface CliFlagOptions {
44
+ /** A one-letter short form, without the dash. */
45
+ short?: string;
46
+ /** More long names, without the dashes. Shown in help only when not hidden. */
47
+ aliases?: readonly string[];
48
+ /** Keeps the flag out of `--help`. */
49
+ hidden?: boolean;
50
+ }
51
+ /** How agents see an intent through MCP. */
52
+ export interface AgentSection {
53
+ /** The tool name. Default: the intent's name with dots as underscores (`namespace_list`). */
54
+ tool?: string;
55
+ /** When and how to use it. */
56
+ usage?: string;
57
+ /** When not to use it, and what to use instead. */
58
+ whenNotToUse?: string;
59
+ /** Keeps it out of MCP. */
60
+ hidden?: boolean;
61
+ }
62
+ /** The handler module an intent can load lazily, so `--help` never imports command code. */
63
+ export type IntentHandlerModule<In, Result> = IntentHandler<In, Result> | {
64
+ default: IntentHandler<In, Result>;
65
+ } | {
66
+ handle: IntentHandler<In, Result>;
67
+ };
68
+ /** The input type an intent's handler receives: the declared type, or the schema's output. */
69
+ export type IntentInputOf<N extends string, S> = N extends keyof SousIntents ? IntentInput<N> : InferOutput<S>;
70
+ /**
71
+ * An intent: a step a user or another plugin asks for, with a typed input and one handler. The CLI's commands and flags and the MCP server's tools are generated from it.
72
+ *
73
+ * Give either `handle`, or `load` to import the handler only when the intent runs.
74
+ */
75
+ export interface IntentDefinition<N extends string = string, S extends SousSchema = SousSchema> {
76
+ /** The name, `<plugin>.<verb>`: `diagrams.render`, `subscription.add`. */
77
+ intent: N;
78
+ /** One sentence saying what it does, for help, tools and the web GUI. */
79
+ summary?: string;
80
+ /** More about it, for `--help`. */
81
+ description?: string;
82
+ /** The input schema. Every input is a flag. Default: no input. */
83
+ input?: S;
84
+ /** The result schema, for front ends that describe results (MCP). */
85
+ output?: SousSchema;
86
+ /** Runs outside the scheduler, such as `mcp.serve`; it submits chains instead of using `ctx.run`. */
87
+ background?: boolean;
88
+ /** A chain started with this intent may run beside other parallel chains: it writes nothing others read. */
89
+ parallel?: boolean;
90
+ /** Running it changes the config, so the engine rebuilds the config before the next chain. */
91
+ changesConfig?: boolean;
92
+ /**
93
+ * It can run when the config fails to build (`sous update` repairing a broken install): it runs
94
+ * with whatever partial config the failed build reached (the plugins it activated, the values
95
+ * it merged, unchecked), and the build's error is reported as a warning. Other intents fail
96
+ * with that error.
97
+ */
98
+ toleratesConfigErrors?: boolean;
99
+ /**
100
+ * `boolean = false`. It reads nothing from the config's values, only from what the built-in
101
+ * plugins registered (the command tree, the version), so the front end may run it before the
102
+ * config is built, when the project loads no plugin beyond the built-in ones.
103
+ */
104
+ runsWithoutConfig?: boolean;
105
+ /**
106
+ * It works on a project, so it fails, before it runs, when sous was started outside one: the
107
+ * error says no sous config was found and how to set a project up.
108
+ */
109
+ requiresProject?: boolean;
110
+ /** Only callable through `ctx.run`; neither the CLI nor MCP shows it. */
111
+ internal?: boolean;
112
+ /** How the CLI shows it. */
113
+ cli?: CliSection;
114
+ /** How agents see it. */
115
+ agent?: AgentSection;
116
+ /** Runs the intent and returns its outputs: `new IntentOutputs(new IntentOutput({ ... }))`. */
117
+ handle?: IntentHandler<IntentInputOf<N, S>, IntentReturn<N>>;
118
+ /** Imports the handler when the intent first runs. */
119
+ load?: () => Promise<IntentHandlerModule<IntentInputOf<N, S>, IntentReturn<N>>>;
120
+ }
121
+ /** An intent and the plugin that added it, as front ends see it. */
122
+ export interface IntentInfo {
123
+ readonly definition: IntentDefinition;
124
+ /** The plugin that added it. */
125
+ readonly plugin: string;
126
+ }
127
+ /** What front ends read about the intents: every one that is loaded and active. */
128
+ export interface IntentCatalog {
129
+ /** Every active intent, in plugin order. */
130
+ list(): IntentInfo[];
131
+ /** One intent, or `undefined`. */
132
+ get(name: string): IntentInfo | undefined;
133
+ }
134
+ /** Asking the engine to run an intent. */
135
+ export interface IntentRequest<N extends string = string> {
136
+ intent: N;
137
+ input?: IntentInput<N> | Record<string, unknown>;
138
+ }
139
+ /** How a front end submits a chain. */
140
+ export interface SubmitOptions {
141
+ /** Where the chain's output goes. Default: the engine's reporter. */
142
+ reporter?: Reporter;
143
+ /** Where the chain's questions go. Default: a prompter that cannot ask. */
144
+ prompter?: Prompter;
145
+ /** Declares the chain parallel. Default: what the intent declares. */
146
+ parallel?: boolean;
147
+ /** Values of the front end's global arguments (`--debug`, plugin-added ones), as `ctx.globals`. */
148
+ globals?: Readonly<Record<string, unknown>>;
149
+ /** The working directory, as `ctx.cwd` (the CLI: the process's; MCP: the project root). Default: the engine's. */
150
+ cwd?: string;
151
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/json.d.ts ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Plain JSON values, and the patches that change them.
3
+ *
4
+ * The config is always plain JSON, and every change to it, or to any
5
+ * document a plugin edits, is a list of primitive patches.
6
+ */
7
+ /** A plain JSON value. */
8
+ export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
9
+ /** A JSON scalar. */
10
+ export type JsonPrimitive = string | number | boolean | null;
11
+ /** A JSON array. */
12
+ export type JsonArray = JsonValue[];
13
+ /** A JSON object. */
14
+ export interface JsonObject {
15
+ [key: string]: JsonValue;
16
+ }
17
+ /** One step of a path: an object key, or an array index. */
18
+ export type PathSegment = string | number;
19
+ /**
20
+ * A path, as segments (`["subscriptions", "workflow/x", "enabled"]`) or as a string
21
+ * (`subscriptions."workflow/x".enabled`, `compilation.targets[7].id`). `""` and `[]` name the root.
22
+ */
23
+ export type PathInput = string | readonly PathSegment[];
24
+ /** Sets one key of an object, creating missing objects along the path. */
25
+ export interface SetKeyPatch {
26
+ op: "setKey";
27
+ /** The object holding the key, as a canonical path string. */
28
+ path: string;
29
+ key: string;
30
+ value: JsonValue;
31
+ }
32
+ /** Deletes one key of an object. Deleting a missing key does nothing. */
33
+ export interface DeleteKeyPatch {
34
+ op: "deleteKey";
35
+ path: string;
36
+ key: string;
37
+ }
38
+ /** Renames one key of an object, keeping its place. An existing key named `to` is replaced. */
39
+ export interface RenameKeyPatch {
40
+ op: "renameKey";
41
+ path: string;
42
+ key: string;
43
+ to: string;
44
+ }
45
+ /** Sets one item of an array. */
46
+ export interface SetIndexPatch {
47
+ op: "setIndex";
48
+ path: string;
49
+ index: number;
50
+ value: JsonValue;
51
+ }
52
+ /**
53
+ * Inserts one item into an array, creating the array when it is missing. `"end"` appends, so an
54
+ * append never depends on the array's length when the patch was made.
55
+ */
56
+ export interface InsertAtPatch {
57
+ op: "insertAt";
58
+ path: string;
59
+ index: number | "end";
60
+ value: JsonValue;
61
+ }
62
+ /** Removes one item from an array. */
63
+ export interface RemoveIndexPatch {
64
+ op: "removeIndex";
65
+ path: string;
66
+ index: number;
67
+ }
68
+ /** One primitive operation. Every other operation is a helper built on these. */
69
+ export type Patch = SetKeyPatch | DeleteKeyPatch | RenameKeyPatch | SetIndexPatch | InsertAtPatch | RemoveIndexPatch;
70
+ /** The name of a primitive operation. */
71
+ export type PatchOp = Patch["op"];
72
+ /**
73
+ * A named group of patches and other patch sets. A helper's work is one patch set
74
+ * (`removeWhere compilation.targets`), and one contributor run produces one patch set.
75
+ */
76
+ export interface PatchSet {
77
+ /** What made it: a helper name (`removeWhere`) or a contributor id (`confd/610-mac.jsonc`). */
78
+ name: string;
79
+ /** The path the helper worked on, when it worked on one. */
80
+ path?: string;
81
+ patches: Array<Patch | PatchSet>;
82
+ }
83
+ /** The kind of a JSON value. */
84
+ export type ValueType = "object" | "array" | "string" | "number" | "boolean" | "null";
package/dist/json.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Plain JSON values, and the patches that change them.
3
+ *
4
+ * The config is always plain JSON, and every change to it, or to any
5
+ * document a plugin edits, is a list of primitive patches.
6
+ */
7
+ export {};
package/dist/node.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ import type { JsonValue, PathInput, PathSegment, ValueType } from "./json.js";
2
+ /**
3
+ * One place in a document, or in the config while it is built: the operations listed in "The
4
+ * Document-Editing Package". Inspecting methods read the value (the config builder records each
5
+ * read); every change becomes primitive patches.
6
+ *
7
+ * ```ts
8
+ * const targets = config.atPath("compilation.targets");
9
+ *
10
+ * if (targets.isArray()) {
11
+ * targets.removeWhere((target) => target.id === "diagrams");
12
+ * }
13
+ *
14
+ * targets.append({ id: "diagrams", entryGlob: "docs/**\/*.mmd" });
15
+ * ```
16
+ */
17
+ export interface DocumentNode {
18
+ /** The path of this node, as segments. */
19
+ readonly path: readonly PathSegment[];
20
+ /** The path of this node, as a canonical string (`compilation.targets[7]`). */
21
+ readonly pathString: string;
22
+ /** A node below this one. */
23
+ atPath(path: PathInput): DocumentNode;
24
+ /** The item at an index of this array node. */
25
+ atIndex(index: number): DocumentNode;
26
+ /** The node holding this one; the root's parent is the root. */
27
+ parent(): DocumentNode;
28
+ /** Whether a value exists here. */
29
+ exists(): boolean;
30
+ /** The kind of value here, or `"missing"`. */
31
+ type(): ValueType | "missing";
32
+ isArray(): boolean;
33
+ isObject(): boolean;
34
+ /** The value here, or `undefined` when missing. */
35
+ get<T = JsonValue>(): T | undefined;
36
+ /** The value here, or the fallback when missing. */
37
+ valueOr<T>(fallback: T): T;
38
+ /** The keys of this object node; `[]` for anything else. */
39
+ keys(): string[];
40
+ /** The number of items of this array node; `0` for anything else. */
41
+ length(): number;
42
+ /** Sets the value here. `undefined` deletes it. Never reads. */
43
+ set(value: unknown): void;
44
+ /** The same as {@link set}, under the name the examples use. */
45
+ setValue(value: unknown): void;
46
+ /** Deletes the value here. Never reads. */
47
+ delete(): void;
48
+ /** Renames this node's key, keeping its place. Never reads. */
49
+ rename(newKey: string): void;
50
+ /** Merges an object key by key, joining arrays. Reads every key it touches. */
51
+ merge(data: unknown): void;
52
+ /** Replaces the value here whole. */
53
+ replace(value: unknown): void;
54
+ /** Appends an item, creating the array when missing. Never reads. */
55
+ append(item: unknown): void;
56
+ /** The same as {@link append}, under the name the examples use. */
57
+ appendValue(item: unknown): void;
58
+ /** Inserts an item first. Never reads. */
59
+ prepend(item: unknown): void;
60
+ /** The same as {@link prepend}. */
61
+ prependValue(item: unknown): void;
62
+ /** Inserts an item at an index. Never reads. */
63
+ insertAt(index: number, item: unknown): void;
64
+ /** Removes the item at an index. Never reads. */
65
+ removeAt(index: number): void;
66
+ /** Removes every matching item, highest index first. */
67
+ removeWhere(predicate: (item: any, index: number) => boolean): void;
68
+ /** Replaces the first matching item, or appends the item when nothing matches. */
69
+ upsertWhere(predicate: (item: any, index: number) => boolean, item: unknown): void;
70
+ /** A node for the first matching item, to edit in place. */
71
+ findWhere(predicate: (item: any, index: number) => boolean): DocumentNode | undefined;
72
+ /** Moves an item from one index to another. */
73
+ move(from: number, to: number): void;
74
+ /** Removes repeated items, keeping the first of each. */
75
+ dedupe(by?: (item: any) => unknown): void;
76
+ /**
77
+ * Runs a helper of your own: the primitives it makes are grouped in a patch set with this name
78
+ * and this node's path, so `--layers` shows them under it.
79
+ */
80
+ patchSet(name: string, helper: (node: DocumentNode) => void): void;
81
+ }
package/dist/node.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,193 @@
1
+ /**
2
+ * What an intent returns: `IntentOutputs`, one or more `IntentOutput`s in the order they are shown.
3
+ * Each output carries a result as a payload type a reporter knows how to show (`VariableSet`,
4
+ * `Table`, ...), and converts to plain values for machines (`--json`, MCP, a calling intent).
5
+ *
6
+ * A payload is also what a reporter is given to show a structure while an intent runs:
7
+ * `reporter.variables(...)` reports a `VariableSet`.
8
+ */
9
+ import type { ReportEntryStyle, TableColumn, TreeNode, VariableEntry } from "./report-styles.js";
10
+ /** Marks a payload, so a reporter recognizes one even from another copy of this package. */
11
+ declare const PAYLOAD: unique symbol;
12
+ /** Marks an `IntentOutputs`, for the same reason. */
13
+ declare const OUTPUTS: unique symbol;
14
+ /** A plain object: what `toPlain()` returns. */
15
+ export type PlainObject = Record<string, unknown>;
16
+ /**
17
+ * A structure a reporter knows how to show. Each payload holds plain values only, and converts to
18
+ * them: `toPlain()` gives a plain object, and each type adds its own conversion (`toObject()`,
19
+ * `toRows()`, ...). `toText()` is the payload as plain text, for a reporter that draws nothing.
20
+ */
21
+ export declare abstract class Payload {
22
+ /** Which payload type this is, so a reporter can show it without `instanceof`. */
23
+ abstract readonly kind: string;
24
+ readonly [PAYLOAD] = true;
25
+ /** The payload as a plain object. */
26
+ abstract toPlain(): PlainObject;
27
+ /** The payload as plain text, one line per entry. */
28
+ abstract toText(): string;
29
+ /** Whether a value is a payload, from any copy of plugin-api. */
30
+ static is(value: unknown): value is Payload;
31
+ }
32
+ /** Labels and values, read as one block: `Repository: /work/recipes`. */
33
+ export declare class VariableSet extends Payload {
34
+ readonly kind = "variable-set";
35
+ readonly entries: readonly VariableEntry[];
36
+ readonly title: string | undefined;
37
+ /** @param entries - The pairs, or a record read as label and value pairs in its key order. */
38
+ constructor(entries: readonly VariableEntry[] | Readonly<Record<string, unknown>>, options?: {
39
+ title?: string;
40
+ });
41
+ /** The pairs as one object: `{ Repository: "/work/recipes" }`. A label used twice keeps its last value. */
42
+ toObject(): PlainObject;
43
+ toPlain(): PlainObject;
44
+ toText(): string;
45
+ }
46
+ /** Rows under columns. */
47
+ export declare class Table extends Payload {
48
+ readonly kind = "table";
49
+ readonly columns: readonly TableColumn[];
50
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
51
+ readonly title: string | undefined;
52
+ /** What to say instead of the table when there are no rows. */
53
+ readonly empty: string | undefined;
54
+ /** A note shown under a row, by the row's index; `undefined` for a row with none. */
55
+ readonly rowNotes: readonly (string | undefined)[] | undefined;
56
+ constructor(columns: readonly TableColumn[], rows: readonly Readonly<Record<string, unknown>>[], options?: {
57
+ title?: string;
58
+ empty?: string;
59
+ rowNotes?: readonly (string | undefined)[];
60
+ });
61
+ /** The rows. */
62
+ toRows(): Readonly<Record<string, unknown>>[];
63
+ toPlain(): PlainObject;
64
+ toText(): string;
65
+ }
66
+ /** A list of items, with an optional title before it and an optional sentence after it. */
67
+ export declare class ItemList extends Payload {
68
+ readonly kind = "item-list";
69
+ readonly items: readonly string[];
70
+ readonly title: string | undefined;
71
+ readonly footer: string | undefined;
72
+ constructor(items: readonly string[], options?: {
73
+ title?: string;
74
+ footer?: string;
75
+ });
76
+ /** The items. */
77
+ toArray(): string[];
78
+ toPlain(): PlainObject;
79
+ toText(): string;
80
+ }
81
+ /** Items nested under other items. */
82
+ export declare class Tree extends Payload {
83
+ readonly kind = "tree";
84
+ readonly nodes: readonly TreeNode[];
85
+ readonly title: string | undefined;
86
+ constructor(nodes: readonly TreeNode[], options?: {
87
+ title?: string;
88
+ });
89
+ toPlain(): PlainObject;
90
+ toText(): string;
91
+ }
92
+ /**
93
+ * Text. A paragraph a reporter may wrap, or, with `verbatim`, text shown exactly as given (a value
94
+ * a script reads, `--help`).
95
+ */
96
+ export declare class TextBlock extends Payload {
97
+ readonly kind = "text-block";
98
+ readonly text: string;
99
+ readonly verbatim: boolean;
100
+ constructor(text: string, options?: {
101
+ verbatim?: boolean;
102
+ });
103
+ toString(): string;
104
+ toPlain(): PlainObject;
105
+ toText(): string;
106
+ }
107
+ /** A structured value shown as data (a config as JSON). */
108
+ export declare class DataValue extends Payload {
109
+ readonly kind = "data-value";
110
+ readonly value: unknown;
111
+ constructor(value: unknown);
112
+ /** The value itself. */
113
+ toValue(): unknown;
114
+ /** The value when it is a plain object, else `{ value }`. */
115
+ toPlain(): PlainObject;
116
+ toText(): string;
117
+ }
118
+ /** What one {@link IntentOutput} holds. */
119
+ export interface IntentOutputInit<T extends object = object> {
120
+ /** A title above it, for people. */
121
+ readonly title?: string;
122
+ /** One or two sentences saying what it is or what happened, for people. */
123
+ readonly summary?: string;
124
+ /** The result, as a payload a reporter knows how to show. */
125
+ readonly result?: Payload;
126
+ /** What machines get (`--json`, MCP, a calling intent). Default: `result.toPlain()`. */
127
+ readonly data?: T;
128
+ /** A hint for the reporter about what this output is (`ReportEntryStyle.CommandVariables`, ...). */
129
+ readonly style?: ReportEntryStyle;
130
+ }
131
+ /** One part of what an intent returns. */
132
+ export declare class IntentOutput<T extends object = object> {
133
+ readonly title: string | undefined;
134
+ readonly summary: string | undefined;
135
+ readonly result: Payload | undefined;
136
+ readonly data: T | undefined;
137
+ readonly style: ReportEntryStyle | undefined;
138
+ constructor(init: IntentOutputInit<T>);
139
+ /** What machines get: `data`, else the result as a plain object, else `{}`. */
140
+ toPlain(): T;
141
+ /** The output as plain text: title, summary, then the result. */
142
+ toText(): string;
143
+ }
144
+ /**
145
+ * What an intent returns: its outputs, in the order they are shown.
146
+ *
147
+ * ```ts
148
+ * return new IntentOutputs(new IntentOutput({ summary: "Subscribed to acme/git.", result: new VariableSet({ Recipe: "acme/git" }) }));
149
+ *
150
+ * const prepared = (await ctx.run("build.prepare", {})).toPlain(); // the last output's plain object
151
+ * ```
152
+ */
153
+ export declare class IntentOutputs<T extends object = PlainObject> implements Iterable<IntentOutput> {
154
+ #private;
155
+ readonly [OUTPUTS] = true;
156
+ /** The exit code the command ends with (a build with errors ends with 1). Default: none, so 0. */
157
+ readonly exitCode: number | undefined;
158
+ constructor(outputs?: IntentOutput | readonly IntentOutput[], options?: {
159
+ exitCode?: number;
160
+ });
161
+ /** Outputs holding one plain value and nothing to show beyond it. */
162
+ static of<T extends object>(data: T, init?: Omit<IntentOutputInit<T>, "data">): IntentOutputs<T>;
163
+ /** Whether a value is an `IntentOutputs`, from any copy of plugin-api. */
164
+ static is(value: unknown): value is IntentOutputs;
165
+ /** How many outputs there are. */
166
+ get length(): number;
167
+ /** The outputs, in order. */
168
+ toArray(): IntentOutput[];
169
+ /** The first output, or `undefined`. */
170
+ first(): IntentOutput | undefined;
171
+ /** The last output, or `undefined`. */
172
+ last(): IntentOutput | undefined;
173
+ /** The last output's plain object (`{}` with none). Never an array. */
174
+ toPlain(): T;
175
+ /** Every output as plain text, separated by a blank line. */
176
+ toText(): string;
177
+ /** New outputs with more appended, keeping the exit code (for a wrapper or an `after` listener). */
178
+ with(...more: IntentOutput[]): IntentOutputs<T>;
179
+ /**
180
+ * The same outputs with `data` as what machines get: set on the last output, or as one output
181
+ * holding only data when there is none. Use it when the last output shows something built from
182
+ * a larger result.
183
+ *
184
+ * ```ts
185
+ * return new IntentOutputs([commandVariables(ctx), table]).withData({ subscriptions });
186
+ * ```
187
+ */
188
+ withData<D extends object>(data: D): IntentOutputs<D>;
189
+ /** The same outputs with another exit code. */
190
+ withExitCode(exitCode: number): IntentOutputs<T>;
191
+ [Symbol.iterator](): Iterator<IntentOutput>;
192
+ }
193
+ export {};