@db-lyon/flowkit 0.12.0 → 0.13.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 +386 -375
- package/dist/.tsbuildinfo +1 -0
- package/dist/flow/references.d.ts +39 -0
- package/dist/flow/references.d.ts.map +1 -0
- package/dist/flow/references.js +102 -0
- package/dist/flow/references.js.map +1 -0
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +6 -0
- package/dist/references.js.map +1 -1
- package/dist/task/shell-task.d.ts +2 -0
- package/dist/task/shell-task.d.ts.map +1 -1
- package/dist/task/shell-task.js +186 -40
- package/dist/task/shell-task.js.map +1 -1
- package/dist/task/shell-termination.d.ts +34 -0
- package/dist/task/shell-termination.d.ts.map +1 -0
- package/dist/task/shell-termination.js +179 -0
- package/dist/task/shell-termination.js.map +1 -0
- package/docs/ai-agents.md +368 -368
- package/docs/api-reference.md +458 -430
- package/docs/configuration.md +347 -347
- package/docs/custom-tasks.md +258 -232
- package/package.json +53 -52
package/docs/custom-tasks.md
CHANGED
|
@@ -1,232 +1,258 @@
|
|
|
1
|
-
# Custom tasks
|
|
2
|
-
|
|
3
|
-
Tasks are the building blocks of flowkit. Each task is a class that extends `BaseTask` and implements an `execute()` method.
|
|
4
|
-
|
|
5
|
-
## Anatomy of a task
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import { BaseTask, type TaskResult } from '@db-lyon/flowkit';
|
|
9
|
-
|
|
10
|
-
interface MyOptions {
|
|
11
|
-
url: string;
|
|
12
|
-
retries?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default class FetchData extends BaseTask<MyOptions> {
|
|
16
|
-
get taskName() {
|
|
17
|
-
return 'fetch_data';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected validate() {
|
|
21
|
-
if (!this.options.url) {
|
|
22
|
-
throw new Error('url option is required');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async execute(): Promise<TaskResult> {
|
|
27
|
-
const { url, retries = 3 } = this.options;
|
|
28
|
-
|
|
29
|
-
const response = await fetch(url);
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
return {
|
|
32
|
-
success: false,
|
|
33
|
-
error: new Error(`HTTP ${response.status}`),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const data = await response.json();
|
|
38
|
-
return {
|
|
39
|
-
success: true,
|
|
40
|
-
data: { body: data, status: response.status },
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Required members
|
|
47
|
-
|
|
48
|
-
| Member | Description |
|
|
49
|
-
|--------|-------------|
|
|
50
|
-
| `get taskName()` | A human-readable name used in logging |
|
|
51
|
-
| `execute()` | Async method that performs the work and returns a `TaskResult` |
|
|
52
|
-
|
|
53
|
-
### Optional members
|
|
54
|
-
|
|
55
|
-
| Member | Description |
|
|
56
|
-
|--------|-------------|
|
|
57
|
-
| `validate()` | Called before `execute()`. Throw to abort with a validation error. |
|
|
58
|
-
|
|
59
|
-
### Available on `this`
|
|
60
|
-
|
|
61
|
-
| Property | Description |
|
|
62
|
-
|----------|-------------|
|
|
63
|
-
| `this.options` | The merged options (task defaults + step overrides), typed as `TOptions` |
|
|
64
|
-
| `this.ctx` | The `TaskContext` passed to the flow runner — read-only, see below |
|
|
65
|
-
| `this.logger` | A child logger scoped to this task instance |
|
|
66
|
-
| `this.resolve(name, options?)` | Build another task by configured name or class path, unexecuted |
|
|
67
|
-
| `this.call(name, options?)` | `resolve()` plus `run()`, returning its `TaskResult` |
|
|
68
|
-
|
|
69
|
-
## Calling other tasks
|
|
70
|
-
|
|
71
|
-
`this.call(name)` resolves `name` the same way a flow step does. A configured task name is looked up in the `tasks:` config and dispatched through its `class_path`, inheriting its configured `options` as defaults; anything you pass as `options` merges over them and wins. A name with no configured entry resolves as a class path directly, so a bare `vendor.tasks.Thing` still works.
|
|
72
|
-
|
|
73
|
-
```yaml
|
|
74
|
-
tasks:
|
|
75
|
-
soql_query:
|
|
76
|
-
class_path: caseops.tasks.SoqlQuery
|
|
77
|
-
options:
|
|
78
|
-
org: ${org.username}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
// Runs caseops.tasks.SoqlQuery with { org: 'admin@example.com', query: 'SELECT ...' }
|
|
83
|
-
const result = await this.call('soql_query', { query: 'SELECT Id FROM Case' });
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
The `${ns.path}` references in those configured defaults are interpolated for you, against the same scope the calling task itself runs under. The `options` you pass are your own runtime data and are **never** interpolated, so a `${...}` you computed reaches the task verbatim rather than being reinterpreted as configuration.
|
|
87
|
-
|
|
88
|
-
Calling a task requires a registry on the context, which `FlowRunner` supplies. A task constructed by hand without one throws.
|
|
89
|
-
|
|
90
|
-
## The task lifecycle
|
|
91
|
-
|
|
92
|
-
When `task.run()` is called (by the flow runner):
|
|
93
|
-
|
|
94
|
-
1. `validate()` runs — throw here to reject bad options
|
|
95
|
-
2. `execute()` runs — return a `TaskResult`
|
|
96
|
-
3. The result gets a `duration` field added automatically
|
|
97
|
-
4. If `validate()` or `execute()` throws, the error is caught and returned as `{ success: false, error }`
|
|
98
|
-
|
|
99
|
-
You never call `run()` yourself in normal usage — the flow runner handles it.
|
|
100
|
-
|
|
101
|
-
## TaskResult
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
interface TaskResult {
|
|
105
|
-
success: boolean;
|
|
106
|
-
data?: Record<string, unknown>; // arbitrary output data
|
|
107
|
-
error?: Error; // populated on failure
|
|
108
|
-
duration?: number; // milliseconds, set by run()
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Return `{ success: true }` for success and `{ success: false, error }` for expected failures. Unexpected exceptions are caught automatically.
|
|
113
|
-
|
|
114
|
-
## TaskContext
|
|
115
|
-
|
|
116
|
-
The context carries host-supplied state to every task in a flow run — database connections, API clients, configuration:
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
const runner = new FlowRunner({
|
|
120
|
-
// ...
|
|
121
|
-
context: {
|
|
122
|
-
logger: myLogger,
|
|
123
|
-
db: databaseConnection,
|
|
124
|
-
apiKey: process.env.API_KEY,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Inside a task:
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
async execute(): Promise<TaskResult> {
|
|
133
|
-
const db = this.ctx.db as Database;
|
|
134
|
-
// ...
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Treat the context as read-only. Each task is handed its own derived context, so assigning a key inside a task (`this.ctx.cached = x`) does not reach the next step, another task, or a sub-agent. To share mutable state, put a mutable object on the context up front and write into that:
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
context: { cache: new Map() } // this.ctx.cache.set(...) is visible everywhere
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Registering tasks
|
|
145
|
-
|
|
146
|
-
### By name
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
const registry = new TaskRegistry();
|
|
150
|
-
registry.register('fetch_data', FetchData as any);
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
The YAML can then reference it directly:
|
|
154
|
-
|
|
155
|
-
```yaml
|
|
156
|
-
tasks:
|
|
157
|
-
fetch_data:
|
|
158
|
-
class_path: fetch_data
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### By class path
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
registry.registerClassPath('my.tasks.FetchData', FetchData as any);
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Bulk registration
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
registry.registerAll({
|
|
171
|
-
fetch_data: FetchData as any,
|
|
172
|
-
transform: TransformData as any,
|
|
173
|
-
upload: Upload as any,
|
|
174
|
-
});
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Dynamic resolution
|
|
178
|
-
|
|
179
|
-
If a `class_path` isn't found in the registry, flowkit converts dots to path separators and looks for a file on disk:
|
|
180
|
-
|
|
181
|
-
| class_path | Files checked |
|
|
182
|
-
|------------|---------------|
|
|
183
|
-
| `tasks.FetchData` | `tasks/FetchData.ts`, `tasks/FetchData.js`, `tasks/FetchData/index.ts`, `tasks/FetchData/index.js` |
|
|
184
|
-
| `lib.etl.Extract` | `lib/etl/Extract.ts`, `lib/etl/Extract.js`, ... |
|
|
185
|
-
|
|
186
|
-
The module must have either a `default` export or a named export matching the last segment of the path (e.g., `FetchData`). The export must extend `BaseTask`.
|
|
187
|
-
|
|
188
|
-
## Built-in: ShellTask
|
|
189
|
-
|
|
190
|
-
`ShellTask` executes shell commands
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
1
|
+
# Custom tasks
|
|
2
|
+
|
|
3
|
+
Tasks are the building blocks of flowkit. Each task is a class that extends `BaseTask` and implements an `execute()` method.
|
|
4
|
+
|
|
5
|
+
## Anatomy of a task
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { BaseTask, type TaskResult } from '@db-lyon/flowkit';
|
|
9
|
+
|
|
10
|
+
interface MyOptions {
|
|
11
|
+
url: string;
|
|
12
|
+
retries?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default class FetchData extends BaseTask<MyOptions> {
|
|
16
|
+
get taskName() {
|
|
17
|
+
return 'fetch_data';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected validate() {
|
|
21
|
+
if (!this.options.url) {
|
|
22
|
+
throw new Error('url option is required');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async execute(): Promise<TaskResult> {
|
|
27
|
+
const { url, retries = 3 } = this.options;
|
|
28
|
+
|
|
29
|
+
const response = await fetch(url);
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
error: new Error(`HTTP ${response.status}`),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
data: { body: data, status: response.status },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Required members
|
|
47
|
+
|
|
48
|
+
| Member | Description |
|
|
49
|
+
|--------|-------------|
|
|
50
|
+
| `get taskName()` | A human-readable name used in logging |
|
|
51
|
+
| `execute()` | Async method that performs the work and returns a `TaskResult` |
|
|
52
|
+
|
|
53
|
+
### Optional members
|
|
54
|
+
|
|
55
|
+
| Member | Description |
|
|
56
|
+
|--------|-------------|
|
|
57
|
+
| `validate()` | Called before `execute()`. Throw to abort with a validation error. |
|
|
58
|
+
|
|
59
|
+
### Available on `this`
|
|
60
|
+
|
|
61
|
+
| Property | Description |
|
|
62
|
+
|----------|-------------|
|
|
63
|
+
| `this.options` | The merged options (task defaults + step overrides), typed as `TOptions` |
|
|
64
|
+
| `this.ctx` | The `TaskContext` passed to the flow runner — read-only, see below |
|
|
65
|
+
| `this.logger` | A child logger scoped to this task instance |
|
|
66
|
+
| `this.resolve(name, options?)` | Build another task by configured name or class path, unexecuted |
|
|
67
|
+
| `this.call(name, options?)` | `resolve()` plus `run()`, returning its `TaskResult` |
|
|
68
|
+
|
|
69
|
+
## Calling other tasks
|
|
70
|
+
|
|
71
|
+
`this.call(name)` resolves `name` the same way a flow step does. A configured task name is looked up in the `tasks:` config and dispatched through its `class_path`, inheriting its configured `options` as defaults; anything you pass as `options` merges over them and wins. A name with no configured entry resolves as a class path directly, so a bare `vendor.tasks.Thing` still works.
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
tasks:
|
|
75
|
+
soql_query:
|
|
76
|
+
class_path: caseops.tasks.SoqlQuery
|
|
77
|
+
options:
|
|
78
|
+
org: ${org.username}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Runs caseops.tasks.SoqlQuery with { org: 'admin@example.com', query: 'SELECT ...' }
|
|
83
|
+
const result = await this.call('soql_query', { query: 'SELECT Id FROM Case' });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The `${ns.path}` references in those configured defaults are interpolated for you, against the same scope the calling task itself runs under. The `options` you pass are your own runtime data and are **never** interpolated, so a `${...}` you computed reaches the task verbatim rather than being reinterpreted as configuration.
|
|
87
|
+
|
|
88
|
+
Calling a task requires a registry on the context, which `FlowRunner` supplies. A task constructed by hand without one throws.
|
|
89
|
+
|
|
90
|
+
## The task lifecycle
|
|
91
|
+
|
|
92
|
+
When `task.run()` is called (by the flow runner):
|
|
93
|
+
|
|
94
|
+
1. `validate()` runs — throw here to reject bad options
|
|
95
|
+
2. `execute()` runs — return a `TaskResult`
|
|
96
|
+
3. The result gets a `duration` field added automatically
|
|
97
|
+
4. If `validate()` or `execute()` throws, the error is caught and returned as `{ success: false, error }`
|
|
98
|
+
|
|
99
|
+
You never call `run()` yourself in normal usage — the flow runner handles it.
|
|
100
|
+
|
|
101
|
+
## TaskResult
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface TaskResult {
|
|
105
|
+
success: boolean;
|
|
106
|
+
data?: Record<string, unknown>; // arbitrary output data
|
|
107
|
+
error?: Error; // populated on failure
|
|
108
|
+
duration?: number; // milliseconds, set by run()
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Return `{ success: true }` for success and `{ success: false, error }` for expected failures. Unexpected exceptions are caught automatically.
|
|
113
|
+
|
|
114
|
+
## TaskContext
|
|
115
|
+
|
|
116
|
+
The context carries host-supplied state to every task in a flow run — database connections, API clients, configuration:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const runner = new FlowRunner({
|
|
120
|
+
// ...
|
|
121
|
+
context: {
|
|
122
|
+
logger: myLogger,
|
|
123
|
+
db: databaseConnection,
|
|
124
|
+
apiKey: process.env.API_KEY,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Inside a task:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
async execute(): Promise<TaskResult> {
|
|
133
|
+
const db = this.ctx.db as Database;
|
|
134
|
+
// ...
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Treat the context as read-only. Each task is handed its own derived context, so assigning a key inside a task (`this.ctx.cached = x`) does not reach the next step, another task, or a sub-agent. To share mutable state, put a mutable object on the context up front and write into that:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
context: { cache: new Map() } // this.ctx.cache.set(...) is visible everywhere
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Registering tasks
|
|
145
|
+
|
|
146
|
+
### By name
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const registry = new TaskRegistry();
|
|
150
|
+
registry.register('fetch_data', FetchData as any);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The YAML can then reference it directly:
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
tasks:
|
|
157
|
+
fetch_data:
|
|
158
|
+
class_path: fetch_data
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### By class path
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
registry.registerClassPath('my.tasks.FetchData', FetchData as any);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Bulk registration
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
registry.registerAll({
|
|
171
|
+
fetch_data: FetchData as any,
|
|
172
|
+
transform: TransformData as any,
|
|
173
|
+
upload: Upload as any,
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Dynamic resolution
|
|
178
|
+
|
|
179
|
+
If a `class_path` isn't found in the registry, flowkit converts dots to path separators and looks for a file on disk:
|
|
180
|
+
|
|
181
|
+
| class_path | Files checked |
|
|
182
|
+
|------------|---------------|
|
|
183
|
+
| `tasks.FetchData` | `tasks/FetchData.ts`, `tasks/FetchData.js`, `tasks/FetchData/index.ts`, `tasks/FetchData/index.js` |
|
|
184
|
+
| `lib.etl.Extract` | `lib/etl/Extract.ts`, `lib/etl/Extract.js`, ... |
|
|
185
|
+
|
|
186
|
+
The module must have either a `default` export or a named export matching the last segment of the path (e.g., `FetchData`). The export must extend `BaseTask`.
|
|
187
|
+
|
|
188
|
+
## Built-in: ShellTask
|
|
189
|
+
|
|
190
|
+
`ShellTask` executes shell commands through the platform shell and streams output.
|
|
191
|
+
Register it under any name you like:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { ShellTask } from '@db-lyon/flowkit';
|
|
195
|
+
|
|
196
|
+
registry.register('shell', ShellTask as any);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Then use it in YAML:
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
tasks:
|
|
203
|
+
lint:
|
|
204
|
+
class_path: shell
|
|
205
|
+
description: Run the linter
|
|
206
|
+
options:
|
|
207
|
+
command: npm run lint
|
|
208
|
+
|
|
209
|
+
build:
|
|
210
|
+
class_path: shell
|
|
211
|
+
description: Build the project
|
|
212
|
+
options:
|
|
213
|
+
command: npm run build
|
|
214
|
+
cwd: /path/to/project
|
|
215
|
+
timeout: 120000
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### ShellTask options
|
|
219
|
+
|
|
220
|
+
| Option | Type | Default | Description |
|
|
221
|
+
|--------|------|---------|-------------|
|
|
222
|
+
| `command` | `string` | (required) | The shell command to execute |
|
|
223
|
+
| `cwd` | `string` | `undefined` | Working directory |
|
|
224
|
+
| `timeout` | `number` | `300000` (5 min) | Timeout in milliseconds |
|
|
225
|
+
| `signal` | `AbortSignal` | `undefined` | Cancels one programmatic invocation; cannot be specified in YAML |
|
|
226
|
+
|
|
227
|
+
On success, `result.data.output` contains the trimmed stdout. On failure, `result.data` includes `exitCode`, `stderr`, and `stdout`.
|
|
228
|
+
|
|
229
|
+
Existing YAML consumers need no change. Programmatic callers that need
|
|
230
|
+
cancellation pass an invocation-specific `AbortSignal` in the task options.
|
|
231
|
+
After cancellation, Flowkit waits for the shell to close, with a bounded
|
|
232
|
+
fallback if the operating system does not report closure (one second on POSIX,
|
|
233
|
+
three seconds on Windows). That fallback does not guarantee all descendants
|
|
234
|
+
have exited. At the deadline Flowkit requests force termination and releases
|
|
235
|
+
its Node handles for the root shell and any Windows `taskkill` helper before
|
|
236
|
+
returning. On POSIX,
|
|
237
|
+
signal-bearing invocations use a dedicated process group: Flowkit requests
|
|
238
|
+
`SIGTERM`, waits 250ms for cooperative cleanup, then escalates the group to
|
|
239
|
+
`SIGKILL`. Terminal Ctrl+C is not delivered to that separate group, so use the
|
|
240
|
+
supplied `AbortSignal` for cancellation.
|
|
241
|
+
|
|
242
|
+
On Windows, Flowkit asks `taskkill /T /F` to terminate the shell tree and does
|
|
243
|
+
not kill the shell while that traversal is in progress. If `taskkill` fails or
|
|
244
|
+
the three-second deadline expires, Flowkit requests force termination and
|
|
245
|
+
releases its Node handles for the root and helper. Windows and POSIX descendants that escape the managed process
|
|
246
|
+
tree or process group may still survive; Node does not provide a portable
|
|
247
|
+
guarantee of complete descendant termination.
|
|
248
|
+
|
|
249
|
+
Trailing stdout and stderr fragments are captured once, including when no
|
|
250
|
+
`signal` is supplied. This corrects the duplicate final-partial-line output in
|
|
251
|
+
earlier releases.
|
|
252
|
+
|
|
253
|
+
## Listing registered tasks
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const names = registry.listRegistered();
|
|
257
|
+
// ['fetch_data', 'shell', 'my.tasks.Transform', ...]
|
|
258
|
+
```
|
package/package.json
CHANGED
|
@@ -1,52 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@db-lyon/flowkit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "YAML-configured task and flow orchestration engine",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./dist/index.js",
|
|
10
|
-
"./config": "./dist/config/index.js",
|
|
11
|
-
"./task": "./dist/task/index.js",
|
|
12
|
-
"./flow": "./dist/flow/index.js",
|
|
13
|
-
"./dag": "./dist/dag/index.js"
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"/dist",
|
|
17
|
-
"/docs"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"build": "tsc -b",
|
|
21
|
-
"prepublishOnly": "tsc -b",
|
|
22
|
-
"test": "vitest run",
|
|
23
|
-
"test:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"@types/
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@db-lyon/flowkit",
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"description": "YAML-configured task and flow orchestration engine",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./config": "./dist/config/index.js",
|
|
11
|
+
"./task": "./dist/task/index.js",
|
|
12
|
+
"./flow": "./dist/flow/index.js",
|
|
13
|
+
"./dag": "./dist/dag/index.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"/dist",
|
|
17
|
+
"/docs"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -b",
|
|
21
|
+
"prepublishOnly": "tsc -b",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:package-api": "npm run build && tsc -p test/tsconfig.public-api.json",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"task",
|
|
28
|
+
"flow",
|
|
29
|
+
"orchestration",
|
|
30
|
+
"yaml",
|
|
31
|
+
"pipeline",
|
|
32
|
+
"engine"
|
|
33
|
+
],
|
|
34
|
+
"author": "David Lyon",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/db-lyon/flowkit.git"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"js-yaml": "^4",
|
|
42
|
+
"zod": "^3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/js-yaml": "^4",
|
|
46
|
+
"@types/node": "^20",
|
|
47
|
+
"typescript": "^5",
|
|
48
|
+
"vitest": "^2"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
52
|
+
}
|
|
53
|
+
}
|