@canonical/summon 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.
- package/README.md +439 -0
- package/generators/example/hello/index.ts +132 -0
- package/generators/example/hello/templates/README.md.ejs +20 -0
- package/generators/example/hello/templates/index.ts.ejs +9 -0
- package/generators/example/webapp/index.ts +509 -0
- package/generators/example/webapp/templates/ARCHITECTURE.md.ejs +180 -0
- package/generators/example/webapp/templates/App.tsx.ejs +86 -0
- package/generators/example/webapp/templates/README.md.ejs +154 -0
- package/generators/example/webapp/templates/app.test.ts.ejs +63 -0
- package/generators/example/webapp/templates/app.ts.ejs +132 -0
- package/generators/example/webapp/templates/feature.ts.ejs +264 -0
- package/generators/example/webapp/templates/index.html.ejs +20 -0
- package/generators/example/webapp/templates/main.tsx.ejs +43 -0
- package/generators/example/webapp/templates/styles.css.ejs +135 -0
- package/generators/init/index.ts +124 -0
- package/generators/init/templates/generator.ts.ejs +85 -0
- package/generators/init/templates/template-index.ts.ejs +9 -0
- package/generators/init/templates/template-test.ts.ejs +8 -0
- package/package.json +64 -0
- package/src/__tests__/combinators.test.ts +895 -0
- package/src/__tests__/dry-run.test.ts +927 -0
- package/src/__tests__/effect.test.ts +816 -0
- package/src/__tests__/interpreter.test.ts +673 -0
- package/src/__tests__/primitives.test.ts +970 -0
- package/src/__tests__/task.test.ts +929 -0
- package/src/__tests__/template.test.ts +666 -0
- package/src/cli-format.ts +165 -0
- package/src/cli-types.ts +53 -0
- package/src/cli.tsx +1322 -0
- package/src/combinators.ts +294 -0
- package/src/completion.ts +488 -0
- package/src/components/App.tsx +960 -0
- package/src/components/ExecutionProgress.tsx +205 -0
- package/src/components/FileTreePreview.tsx +97 -0
- package/src/components/PromptSequence.tsx +483 -0
- package/src/components/Spinner.tsx +36 -0
- package/src/components/index.ts +16 -0
- package/src/dry-run.ts +434 -0
- package/src/effect.ts +224 -0
- package/src/index.ts +266 -0
- package/src/interpreter.ts +463 -0
- package/src/primitives.ts +442 -0
- package/src/task.ts +245 -0
- package/src/template.ts +537 -0
- package/src/types.ts +453 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for the Summon code generator framework.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the fundamental types that power the monadic task system:
|
|
5
|
+
* - Effects: Pure data descriptions of operations
|
|
6
|
+
* - Tasks: The Task monad for composable, testable generators
|
|
7
|
+
* - Errors: Structured error handling
|
|
8
|
+
* - Generator definitions: Schema for defining generators
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Log Levels
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Log levels for the logging primitives.
|
|
19
|
+
*
|
|
20
|
+
* - `debug` - Detailed information, only shown with `--verbose` flag
|
|
21
|
+
* - `info` - General information about generation progress
|
|
22
|
+
* - `warn` - Warning messages for non-fatal issues
|
|
23
|
+
* - `error` - Error messages for failures
|
|
24
|
+
*/
|
|
25
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
26
|
+
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Prompt Types
|
|
29
|
+
// =============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Base interface for all prompt types.
|
|
33
|
+
*/
|
|
34
|
+
export interface PromptQuestionBase {
|
|
35
|
+
/** Unique identifier for this prompt, used as the answer key */
|
|
36
|
+
name: string;
|
|
37
|
+
/** Question text displayed to the user */
|
|
38
|
+
message: string;
|
|
39
|
+
/** Default value if user provides no input */
|
|
40
|
+
default?: unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Free-form text input prompt.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* { name: "projectName", type: "text", message: "Project name:", default: "my-app" }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* CLI: `--project-name=value`
|
|
52
|
+
*/
|
|
53
|
+
export interface TextPrompt extends PromptQuestionBase {
|
|
54
|
+
type: "text";
|
|
55
|
+
default?: string;
|
|
56
|
+
/** Validation function, returns true or error message */
|
|
57
|
+
validate?: (value: string) => boolean | string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Boolean yes/no confirmation prompt.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* { name: "withTests", type: "confirm", message: "Include tests?", default: true }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* CLI: `--with-tests` (enable) or `--no-with-tests` (disable)
|
|
69
|
+
*/
|
|
70
|
+
export interface ConfirmPrompt extends PromptQuestionBase {
|
|
71
|
+
type: "confirm";
|
|
72
|
+
default?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Single selection from a list of choices.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* {
|
|
81
|
+
* name: "framework",
|
|
82
|
+
* type: "select",
|
|
83
|
+
* message: "Framework:",
|
|
84
|
+
* choices: [
|
|
85
|
+
* { label: "React", value: "react" },
|
|
86
|
+
* { label: "Vue", value: "vue" },
|
|
87
|
+
* ],
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* CLI: `--framework=react`
|
|
92
|
+
*/
|
|
93
|
+
export interface SelectPrompt extends PromptQuestionBase {
|
|
94
|
+
type: "select";
|
|
95
|
+
/** Available options to choose from */
|
|
96
|
+
choices: Array<{ label: string; value: string }>;
|
|
97
|
+
default?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Multiple selection from a list of choices.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* {
|
|
106
|
+
* name: "features",
|
|
107
|
+
* type: "multiselect",
|
|
108
|
+
* message: "Features:",
|
|
109
|
+
* choices: [
|
|
110
|
+
* { label: "TypeScript", value: "ts" },
|
|
111
|
+
* { label: "ESLint", value: "eslint" },
|
|
112
|
+
* ],
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* CLI: `--features=ts,eslint`
|
|
117
|
+
*/
|
|
118
|
+
export interface MultiselectPrompt extends PromptQuestionBase {
|
|
119
|
+
type: "multiselect";
|
|
120
|
+
/** Available options to choose from */
|
|
121
|
+
choices: Array<{ label: string; value: string }>;
|
|
122
|
+
default?: string[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Union of all prompt question types.
|
|
127
|
+
*/
|
|
128
|
+
export type PromptQuestion =
|
|
129
|
+
| TextPrompt
|
|
130
|
+
| ConfirmPrompt
|
|
131
|
+
| SelectPrompt
|
|
132
|
+
| MultiselectPrompt;
|
|
133
|
+
|
|
134
|
+
// =============================================================================
|
|
135
|
+
// Effect Types - Pure data descriptions of operations
|
|
136
|
+
// =============================================================================
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Effect represents a pure data description of a side-effecting operation.
|
|
140
|
+
*
|
|
141
|
+
* Effects are not executed directly - they are data structures that describe
|
|
142
|
+
* what should happen. The interpreter (production or dry-run) decides how
|
|
143
|
+
* to actually execute them.
|
|
144
|
+
*
|
|
145
|
+
* Each effect has a `_tag` discriminator for pattern matching.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // WriteFile effect
|
|
150
|
+
* { _tag: "WriteFile", path: "src/index.ts", content: "export {}" }
|
|
151
|
+
*
|
|
152
|
+
* // Log effect
|
|
153
|
+
* { _tag: "Log", level: "info", message: "Creating file..." }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export type Effect =
|
|
157
|
+
/** Read file contents as UTF-8 string */
|
|
158
|
+
| { _tag: "ReadFile"; path: string }
|
|
159
|
+
/** Write content to file, creating parent directories */
|
|
160
|
+
| { _tag: "WriteFile"; path: string; content: string }
|
|
161
|
+
/** Append content to file */
|
|
162
|
+
| {
|
|
163
|
+
_tag: "AppendFile";
|
|
164
|
+
path: string;
|
|
165
|
+
content: string;
|
|
166
|
+
createIfMissing: boolean;
|
|
167
|
+
}
|
|
168
|
+
/** Copy a single file */
|
|
169
|
+
| { _tag: "CopyFile"; source: string; dest: string }
|
|
170
|
+
/** Recursively copy a directory */
|
|
171
|
+
| { _tag: "CopyDirectory"; source: string; dest: string }
|
|
172
|
+
/** Delete a file */
|
|
173
|
+
| { _tag: "DeleteFile"; path: string }
|
|
174
|
+
/** Recursively delete a directory */
|
|
175
|
+
| { _tag: "DeleteDirectory"; path: string }
|
|
176
|
+
/** Create directory and parents */
|
|
177
|
+
| { _tag: "MakeDir"; path: string; recursive: boolean }
|
|
178
|
+
/** Check if path exists */
|
|
179
|
+
| { _tag: "Exists"; path: string }
|
|
180
|
+
/** Find files matching glob pattern */
|
|
181
|
+
| { _tag: "Glob"; pattern: string; cwd: string }
|
|
182
|
+
/** Execute shell command */
|
|
183
|
+
| { _tag: "Exec"; command: string; args: string[]; cwd?: string }
|
|
184
|
+
/** Interactive prompt */
|
|
185
|
+
| { _tag: "Prompt"; question: PromptQuestion }
|
|
186
|
+
/** Log message at specified level */
|
|
187
|
+
| { _tag: "Log"; level: LogLevel; message: string }
|
|
188
|
+
/** Read from task context */
|
|
189
|
+
| { _tag: "ReadContext"; key: string }
|
|
190
|
+
/** Write to task context */
|
|
191
|
+
| { _tag: "WriteContext"; key: string; value: unknown }
|
|
192
|
+
/** Run tasks in parallel */
|
|
193
|
+
| { _tag: "Parallel"; tasks: Task<unknown>[] }
|
|
194
|
+
/** Race tasks, return first to complete */
|
|
195
|
+
| { _tag: "Race"; tasks: Task<unknown>[] };
|
|
196
|
+
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// Task Error
|
|
199
|
+
// =============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Structured error type for task failures.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* {
|
|
207
|
+
* code: "FILE_NOT_FOUND",
|
|
208
|
+
* message: "Cannot read file: src/missing.ts",
|
|
209
|
+
* context: { path: "src/missing.ts" }
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export interface TaskError {
|
|
214
|
+
/** Error code for programmatic handling */
|
|
215
|
+
code: string;
|
|
216
|
+
/** Human-readable error message */
|
|
217
|
+
message: string;
|
|
218
|
+
/** Original error that caused this failure */
|
|
219
|
+
cause?: unknown;
|
|
220
|
+
/** Additional context about the error */
|
|
221
|
+
context?: Record<string, unknown>;
|
|
222
|
+
/** Stack trace if available */
|
|
223
|
+
stack?: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// Task Monad - The core abstraction for composable generators
|
|
228
|
+
// =============================================================================
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The Task monad - the core abstraction for composable, testable generators.
|
|
232
|
+
*
|
|
233
|
+
* A Task is a pure description of a computation that may:
|
|
234
|
+
* - Return a value immediately (Pure)
|
|
235
|
+
* - Perform an effect and continue (Effect)
|
|
236
|
+
* - Fail with an error (Fail)
|
|
237
|
+
*
|
|
238
|
+
* Tasks are lazy - they don't execute until interpreted by `runTask` or `dryRun`.
|
|
239
|
+
*
|
|
240
|
+
* @typeParam A - The type of the value this task produces
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Create a task that writes a file
|
|
245
|
+
* const task: Task<void> = writeFile("hello.txt", "Hello, world!");
|
|
246
|
+
*
|
|
247
|
+
* // Compose tasks
|
|
248
|
+
* const composed: Task<void> = sequence_([
|
|
249
|
+
* mkdir("src"),
|
|
250
|
+
* writeFile("src/index.ts", "export {}"),
|
|
251
|
+
* ]);
|
|
252
|
+
*
|
|
253
|
+
* // Run for real
|
|
254
|
+
* await runTask(task);
|
|
255
|
+
*
|
|
256
|
+
* // Or dry-run for testing
|
|
257
|
+
* const { effects } = dryRun(task);
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export type Task<A> =
|
|
261
|
+
/** Pure value - computation complete */
|
|
262
|
+
| { _tag: "Pure"; value: A }
|
|
263
|
+
/** Effect with continuation - perform effect, then continue */
|
|
264
|
+
| { _tag: "Effect"; effect: Effect; cont: (result: unknown) => Task<A> }
|
|
265
|
+
/** Failure - computation failed with error */
|
|
266
|
+
| { _tag: "Fail"; error: TaskError };
|
|
267
|
+
|
|
268
|
+
// =============================================================================
|
|
269
|
+
// Execution Result
|
|
270
|
+
// =============================================================================
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Result of executing a shell command.
|
|
274
|
+
*/
|
|
275
|
+
export interface ExecResult {
|
|
276
|
+
/** Standard output from the command */
|
|
277
|
+
stdout: string;
|
|
278
|
+
/** Standard error from the command */
|
|
279
|
+
stderr: string;
|
|
280
|
+
/** Exit code (0 = success) */
|
|
281
|
+
exitCode: number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// =============================================================================
|
|
285
|
+
// Generator Definition Types
|
|
286
|
+
// =============================================================================
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Metadata for a generator, displayed in CLI help and discovery.
|
|
290
|
+
*/
|
|
291
|
+
export interface GeneratorMeta {
|
|
292
|
+
/** Generator name, used in CLI path (e.g., "component/react") */
|
|
293
|
+
name: string;
|
|
294
|
+
/** One-line description shown in generator listings */
|
|
295
|
+
description: string;
|
|
296
|
+
/** Semantic version of the generator */
|
|
297
|
+
version: string;
|
|
298
|
+
/** Author name or email */
|
|
299
|
+
author?: string;
|
|
300
|
+
/**
|
|
301
|
+
* Extended help text shown when calling `summon <topic>` (without subgenerator)
|
|
302
|
+
* and in --help. Use this for detailed explanation and examples.
|
|
303
|
+
* Supports markdown-like formatting.
|
|
304
|
+
*/
|
|
305
|
+
help?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Usage examples shown in help. Each example should show a common invocation.
|
|
308
|
+
*/
|
|
309
|
+
examples?: string[];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Definition of a prompt in a generator.
|
|
314
|
+
*
|
|
315
|
+
* Each prompt becomes a CLI flag. The prompt name is converted to kebab-case
|
|
316
|
+
* for the flag (e.g., `componentPath` → `--component-path`).
|
|
317
|
+
*
|
|
318
|
+
* Prompts can also be positional arguments by setting `positional: true`.
|
|
319
|
+
* Only text prompts can be positional, and only one prompt per generator
|
|
320
|
+
* should be marked as positional.
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```typescript
|
|
324
|
+
* // Positional argument - can be used as:
|
|
325
|
+
* // summon component react src/components/Button
|
|
326
|
+
* // or: summon component react --component-path=src/components/Button
|
|
327
|
+
* {
|
|
328
|
+
* name: "componentPath",
|
|
329
|
+
* type: "text",
|
|
330
|
+
* message: "Component path:",
|
|
331
|
+
* positional: true,
|
|
332
|
+
* }
|
|
333
|
+
* ```
|
|
334
|
+
*/
|
|
335
|
+
export interface PromptDefinition {
|
|
336
|
+
/** Unique identifier, used as answer key and CLI flag name */
|
|
337
|
+
name: string;
|
|
338
|
+
/** Question text displayed to the user */
|
|
339
|
+
message: string;
|
|
340
|
+
/** Type of input */
|
|
341
|
+
type: "text" | "confirm" | "select" | "multiselect";
|
|
342
|
+
/** Default value if user provides no input */
|
|
343
|
+
default?: unknown;
|
|
344
|
+
/** Choices for select/multiselect prompts */
|
|
345
|
+
choices?: Array<{ label: string; value: string }>;
|
|
346
|
+
/** Conditional function - prompt is skipped if this returns false */
|
|
347
|
+
when?: (answers: Record<string, unknown>) => boolean;
|
|
348
|
+
/** Validation function, returns true or error message */
|
|
349
|
+
validate?: (value: unknown) => boolean | string;
|
|
350
|
+
/**
|
|
351
|
+
* Group name for organizing options in --help output.
|
|
352
|
+
* Options without a group appear under "Options".
|
|
353
|
+
*/
|
|
354
|
+
group?: string;
|
|
355
|
+
/**
|
|
356
|
+
* If true, this prompt can be provided as a positional argument.
|
|
357
|
+
* Only one prompt per generator should be positional.
|
|
358
|
+
* Only text prompts can be positional.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```bash
|
|
362
|
+
* # With positional: true on componentPath
|
|
363
|
+
* summon component react src/components/Button
|
|
364
|
+
* # Equivalent to:
|
|
365
|
+
* summon component react --component-path=src/components/Button
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
positional?: boolean;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* The complete definition of a generator.
|
|
373
|
+
*
|
|
374
|
+
* A generator has three parts:
|
|
375
|
+
* 1. `meta` - Metadata for CLI display and help
|
|
376
|
+
* 2. `prompts` - Questions to ask the user (become CLI flags)
|
|
377
|
+
* 3. `generate` - Pure function that returns a Task describing what to do
|
|
378
|
+
*
|
|
379
|
+
* @typeParam TAnswers - Type of the answers object passed to generate
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* const generator = {
|
|
384
|
+
* meta: { name: "module", description: "Create a module", version: "1.0.0" },
|
|
385
|
+
* prompts: [{ name: "name", type: "text", message: "Module name:" }],
|
|
386
|
+
* generate: (answers) => writeFile(`src/${answers.name}.ts`, "export {}"),
|
|
387
|
+
* } as const satisfies GeneratorDefinition<{ name: string }>;
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
export interface GeneratorDefinition<TAnswers = Record<string, unknown>> {
|
|
391
|
+
/** Generator metadata for CLI display */
|
|
392
|
+
meta: GeneratorMeta;
|
|
393
|
+
/** Prompts to collect answers from user */
|
|
394
|
+
prompts: PromptDefinition[];
|
|
395
|
+
/** Pure function that returns a Task describing the generation */
|
|
396
|
+
generate: (answers: TAnswers) => Task<void>;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* A generator definition without type parameters, used in barrels/collections.
|
|
401
|
+
* Generators with any answer type can be assigned to this.
|
|
402
|
+
*
|
|
403
|
+
* Uses `never` for contravariant position - since `generate` takes TAnswers as input,
|
|
404
|
+
* a GeneratorDefinition<SpecificAnswers> can accept Record<string, unknown> which
|
|
405
|
+
* is a supertype of SpecificAnswers.
|
|
406
|
+
*/
|
|
407
|
+
// biome-ignore lint/suspicious/noExplicitAny: Required for contravariant generator collections
|
|
408
|
+
export type AnyGenerator = GeneratorDefinition<any>;
|
|
409
|
+
|
|
410
|
+
// =============================================================================
|
|
411
|
+
// Task Event Types (for RxJS integration / progress reporting)
|
|
412
|
+
// =============================================================================
|
|
413
|
+
|
|
414
|
+
export type TaskEvent<A> =
|
|
415
|
+
| { _tag: "Started"; taskId: string; timestamp: number }
|
|
416
|
+
| { _tag: "Progress"; message: string; percent?: number }
|
|
417
|
+
| { _tag: "EffectStarted"; effect: Effect; timestamp: number }
|
|
418
|
+
| { _tag: "EffectCompleted"; effect: Effect; duration: number }
|
|
419
|
+
| { _tag: "Log"; level: LogLevel; message: string }
|
|
420
|
+
| { _tag: "Completed"; value: A; totalDuration: number }
|
|
421
|
+
| { _tag: "Failed"; error: TaskError };
|
|
422
|
+
|
|
423
|
+
// =============================================================================
|
|
424
|
+
// Dry Run Result
|
|
425
|
+
// =============================================================================
|
|
426
|
+
|
|
427
|
+
export interface DryRunResult<A> {
|
|
428
|
+
value: A;
|
|
429
|
+
effects: Effect[];
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// =============================================================================
|
|
433
|
+
// Tracing Types
|
|
434
|
+
// =============================================================================
|
|
435
|
+
|
|
436
|
+
export interface TraceSpan {
|
|
437
|
+
id: string;
|
|
438
|
+
parentId?: string;
|
|
439
|
+
name: string;
|
|
440
|
+
effect?: Effect;
|
|
441
|
+
startTime: number;
|
|
442
|
+
endTime?: number;
|
|
443
|
+
duration?: number;
|
|
444
|
+
status: "pending" | "running" | "completed" | "failed";
|
|
445
|
+
error?: TaskError;
|
|
446
|
+
children: TraceSpan[];
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export interface TraceResult<A> {
|
|
450
|
+
value: A;
|
|
451
|
+
trace: TraceSpan;
|
|
452
|
+
totalDuration: number;
|
|
453
|
+
}
|