agentweaver 0.1.6 → 0.1.8
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/Dockerfile.codex +4 -3
- package/README.md +31 -12
- package/dist/artifacts.js +35 -8
- package/dist/flow-state.js +134 -0
- package/dist/index.js +368 -171
- package/dist/interactive-ui.js +186 -42
- package/dist/pipeline/declarative-flow-runner.js +28 -0
- package/dist/pipeline/flow-specs/auto.json +530 -392
- package/dist/pipeline/flow-specs/bug-analyze.json +149 -0
- package/dist/pipeline/flow-specs/plan.json +133 -0
- package/dist/pipeline/flow-specs/review-project.json +243 -0
- package/dist/pipeline/flow-specs/run-go-linter-loop.json +231 -0
- package/dist/pipeline/flow-specs/run-go-tests-loop.json +231 -0
- package/dist/pipeline/flow-specs/task-describe.json +26 -1
- package/dist/pipeline/node-registry.js +8 -0
- package/dist/pipeline/nodes/jira-issue-check-node.js +53 -0
- package/dist/pipeline/nodes/local-script-check-node.js +50 -8
- package/dist/pipeline/prompt-registry.js +6 -3
- package/dist/pipeline/value-resolver.js +11 -1
- package/dist/prompts.js +16 -2
- package/dist/scope.js +135 -0
- package/dist/structured-artifact-schemas.json +407 -0
- package/dist/structured-artifacts.js +101 -262
- package/docker-compose.yml +65 -4
- package/package.json +4 -3
- package/{run_tests.sh → run_go_coverage.sh} +4 -4
- package/run_go_linter.py +128 -0
- package/run_go_tests.py +120 -0
- package/verify_build.sh +4 -3
- package/run_linter.sh +0 -89
package/Dockerfile.codex
CHANGED
|
@@ -45,9 +45,10 @@ RUN GOBIN=/usr/local/bin go install github.com/golangci/golangci-lint/v2/cmd/gol
|
|
|
45
45
|
ENV PATH="/usr/local/go/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
46
46
|
|
|
47
47
|
COPY verify_build.sh /usr/local/bin/verify_build.sh
|
|
48
|
-
COPY
|
|
49
|
-
COPY
|
|
50
|
-
|
|
48
|
+
COPY run_go_tests.py /usr/local/bin/run_go_tests.py
|
|
49
|
+
COPY run_go_linter.py /usr/local/bin/run_go_linter.py
|
|
50
|
+
COPY run_go_coverage.sh /usr/local/bin/run_go_coverage.sh
|
|
51
|
+
RUN chmod +x /usr/local/bin/verify_build.sh /usr/local/bin/run_go_tests.py /usr/local/bin/run_go_linter.py /usr/local/bin/run_go_coverage.sh
|
|
51
52
|
|
|
52
53
|
WORKDIR /workspace
|
|
53
54
|
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
It orchestrates a flow like:
|
|
6
6
|
|
|
7
|
-
`plan -> implement -> run-linter-loop -> run-tests-loop -> review -> review-fix`
|
|
7
|
+
`plan -> implement -> run-go-linter-loop -> run-go-tests-loop -> review -> review-fix`
|
|
8
8
|
|
|
9
9
|
The package is designed to run as an npm CLI and includes an interactive terminal UI built on `neo-blessed`.
|
|
10
10
|
|
|
@@ -13,8 +13,9 @@ The package is designed to run as an npm CLI and includes an interactive termina
|
|
|
13
13
|
- Fetches a Jira issue by key or browse URL
|
|
14
14
|
- Fetches GitLab merge request review comments into reusable markdown and JSON artifacts
|
|
15
15
|
- Generates workflow artifacts such as design, implementation plan, QA plan, bug analysis, reviews, and summaries
|
|
16
|
-
- Machine-readable JSON artifacts are stored under `.agentweaver
|
|
17
|
-
-
|
|
16
|
+
- Machine-readable JSON artifacts are stored under `.agentweaver/scopes/<scope-key>/.artifacts/` and act as the source of truth between workflow steps; Markdown artifacts remain for human inspection
|
|
17
|
+
- Workflow artifacts are isolated by scope; for Jira-driven flows the scope key defaults to the Jira task key, otherwise it defaults to `<git-branch>--<worktree-hash>`
|
|
18
|
+
- Runs workflow stages like `bug-analyze`, `bug-fix`, `mr-description`, `plan`, `task-describe`, `implement`, `review`, `review-fix`, `run-go-tests-loop`, `run-go-linter-loop`, and `auto`
|
|
18
19
|
- Persists compact `auto` pipeline state on disk so runs can resume without storing large agent outputs
|
|
19
20
|
- Uses Docker runtime services for isolated Codex execution and build verification
|
|
20
21
|
|
|
@@ -25,7 +26,7 @@ The CLI now uses an executor + node + declarative flow architecture.
|
|
|
25
26
|
- `src/index.ts` remains the CLI entrypoint and high-level orchestration layer
|
|
26
27
|
- `src/executors/` contains first-class executors for external actions such as Jira fetch, GitLab review fetch, local Codex, Docker-based build verification, Claude, Claude summaries, and process execution
|
|
27
28
|
- `src/pipeline/nodes/` contains reusable runtime nodes built on top of executors
|
|
28
|
-
- `src/pipeline/flow-specs/` contains declarative JSON flow specs for `preflight`, `bug-analyze`, `bug-fix`, `gitlab-review`, `mr-description`, `plan`, `task-describe`, `implement`, `review`, `review-fix`, `run-tests-loop`, `run-linter-loop`, and `auto`
|
|
29
|
+
- `src/pipeline/flow-specs/` contains declarative JSON flow specs for `preflight`, `bug-analyze`, `bug-fix`, `gitlab-review`, `mr-description`, `plan`, `task-describe`, `implement`, `review`, `review-fix`, `run-go-tests-loop`, `run-go-linter-loop`, and `auto`
|
|
29
30
|
- `src/runtime/` contains shared runtime services such as command resolution, Docker runtime environment setup, and subprocess execution
|
|
30
31
|
|
|
31
32
|
This keeps command handlers focused on choosing a flow and providing parameters instead of assembling prompts and subprocess wiring inline.
|
|
@@ -44,8 +45,9 @@ This keeps command handlers focused on choosing a flow and providing parameters
|
|
|
44
45
|
- `docker-compose.yml` — runtime services for Codex and build verification
|
|
45
46
|
- `Dockerfile.codex` — container image for Codex runtime
|
|
46
47
|
- `verify_build.sh` — aggregated verification entrypoint used by `verify-build`
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
48
|
+
- `run_go_tests.py` — isolated Go test verification entrypoint
|
|
49
|
+
- `run_go_linter.py` — isolated Go generate + lint verification entrypoint
|
|
50
|
+
- `run_go_coverage.sh` — isolated Go coverage verification entrypoint
|
|
49
51
|
- `package.json` — npm package metadata and scripts
|
|
50
52
|
- `tsconfig.json` — TypeScript configuration
|
|
51
53
|
|
|
@@ -117,15 +119,19 @@ Direct CLI usage:
|
|
|
117
119
|
|
|
118
120
|
```bash
|
|
119
121
|
agentweaver plan DEMO-3288
|
|
122
|
+
agentweaver plan
|
|
120
123
|
agentweaver bug-analyze DEMO-3288
|
|
121
124
|
agentweaver bug-fix DEMO-3288
|
|
122
125
|
agentweaver gitlab-review DEMO-3288
|
|
123
126
|
agentweaver mr-description DEMO-3288
|
|
124
127
|
agentweaver task-describe DEMO-3288
|
|
125
128
|
agentweaver implement DEMO-3288
|
|
129
|
+
agentweaver review
|
|
126
130
|
agentweaver review DEMO-3288
|
|
127
|
-
agentweaver
|
|
128
|
-
agentweaver run-
|
|
131
|
+
agentweaver review --scope release-prep
|
|
132
|
+
agentweaver run-go-tests-loop DEMO-3288
|
|
133
|
+
agentweaver run-go-tests-loop
|
|
134
|
+
agentweaver run-go-linter-loop DEMO-3288
|
|
129
135
|
agentweaver auto DEMO-3288
|
|
130
136
|
```
|
|
131
137
|
|
|
@@ -133,11 +139,13 @@ From source checkout:
|
|
|
133
139
|
|
|
134
140
|
```bash
|
|
135
141
|
node dist/index.js plan DEMO-3288
|
|
142
|
+
node dist/index.js plan
|
|
136
143
|
node dist/index.js bug-analyze DEMO-3288
|
|
137
144
|
node dist/index.js bug-fix DEMO-3288
|
|
138
145
|
node dist/index.js gitlab-review DEMO-3288
|
|
139
146
|
node dist/index.js mr-description DEMO-3288
|
|
140
147
|
node dist/index.js task-describe DEMO-3288
|
|
148
|
+
node dist/index.js review
|
|
141
149
|
node dist/index.js auto DEMO-3288
|
|
142
150
|
```
|
|
143
151
|
|
|
@@ -145,6 +153,7 @@ Interactive mode:
|
|
|
145
153
|
|
|
146
154
|
```bash
|
|
147
155
|
agentweaver DEMO-3288
|
|
156
|
+
agentweaver
|
|
148
157
|
```
|
|
149
158
|
|
|
150
159
|
When you run from a working project directory, set `AGENTWEAVER_HOME` to the AgentWeaver installation:
|
|
@@ -165,6 +174,9 @@ agentweaver auto-reset DEMO-3288
|
|
|
165
174
|
Notes:
|
|
166
175
|
|
|
167
176
|
- `--verbose` streams child process `stdout/stderr` in direct CLI mode
|
|
177
|
+
- task-only commands such as `plan` and `auto` ask for Jira task via interactive `user-input` when it is omitted
|
|
178
|
+
- scope-flexible commands such as `review`, `review-fix`, `run-go-tests-loop`, and `run-go-linter-loop` use the current git branch by default when Jira task is omitted
|
|
179
|
+
- `--scope <name>` lets you override the default project scope name
|
|
168
180
|
- the interactive `Activity` pane is intentionally structured: it shows launch separators, prompts, summaries, and short status messages instead of raw Codex/Claude logs by default
|
|
169
181
|
|
|
170
182
|
## Interactive TUI
|
|
@@ -200,8 +212,9 @@ Main services:
|
|
|
200
212
|
- `codex` — interactive Codex container
|
|
201
213
|
- `codex-exec` — non-interactive `codex exec`
|
|
202
214
|
- `verify-build` — project verification script inside container
|
|
203
|
-
- `run-tests` — isolated `
|
|
204
|
-
- `run-linter` — isolated `
|
|
215
|
+
- `run-go-tests` — isolated `run_go_tests.py` execution inside container
|
|
216
|
+
- `run-go-linter` — isolated `run_go_linter.py` execution inside container
|
|
217
|
+
- `run-go-coverage` — isolated `run_go_coverage.sh` execution inside container
|
|
205
218
|
- `codex-login` — interactive login container
|
|
206
219
|
- `dockerd` — internal Docker daemon for testcontainers/build flows
|
|
207
220
|
|
|
@@ -234,13 +247,19 @@ PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run
|
|
|
234
247
|
Tests only:
|
|
235
248
|
|
|
236
249
|
```bash
|
|
237
|
-
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-tests
|
|
250
|
+
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-go-tests
|
|
238
251
|
```
|
|
239
252
|
|
|
240
253
|
Linter only:
|
|
241
254
|
|
|
242
255
|
```bash
|
|
243
|
-
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-linter
|
|
256
|
+
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-go-linter
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Coverage only:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-go-coverage
|
|
244
263
|
```
|
|
245
264
|
|
|
246
265
|
## Development
|
package/dist/artifacts.js
CHANGED
|
@@ -5,23 +5,41 @@ import { TaskRunnerError } from "./errors.js";
|
|
|
5
5
|
export const REVIEW_FILE_RE = /^review-(.+)-(\d+)\.md$/;
|
|
6
6
|
export const REVIEW_REPLY_FILE_RE = /^review-reply-(.+)-(\d+)\.md$/;
|
|
7
7
|
export const READY_TO_MERGE_FILE = "ready-to-merge.md";
|
|
8
|
-
export function
|
|
9
|
-
return path.join(process.cwd(),
|
|
8
|
+
export function scopesRootDir() {
|
|
9
|
+
return path.join(process.cwd(), ".agentweaver", "scopes");
|
|
10
10
|
}
|
|
11
|
-
export function
|
|
12
|
-
|
|
11
|
+
export function scopeWorkspaceDir(scopeKey) {
|
|
12
|
+
return path.join(scopesRootDir(), scopeKey);
|
|
13
|
+
}
|
|
14
|
+
export function ensureScopeWorkspaceDir(scopeKey) {
|
|
15
|
+
const workspaceDir = scopeWorkspaceDir(scopeKey);
|
|
13
16
|
mkdirSync(workspaceDir, { recursive: true });
|
|
14
|
-
mkdirSync(
|
|
17
|
+
mkdirSync(scopeArtifactsDir(scopeKey), { recursive: true });
|
|
15
18
|
return workspaceDir;
|
|
16
19
|
}
|
|
20
|
+
export function scopeWorkspaceFile(scopeKey, fileName) {
|
|
21
|
+
return path.join(scopeWorkspaceDir(scopeKey), fileName);
|
|
22
|
+
}
|
|
23
|
+
export function scopeArtifactsDir(scopeKey) {
|
|
24
|
+
return path.join(scopeWorkspaceDir(scopeKey), ".artifacts");
|
|
25
|
+
}
|
|
26
|
+
export function scopeArtifactsFile(scopeKey, fileName) {
|
|
27
|
+
return path.join(scopeArtifactsDir(scopeKey), fileName);
|
|
28
|
+
}
|
|
29
|
+
export function taskWorkspaceDir(taskKey) {
|
|
30
|
+
return scopeWorkspaceDir(taskKey);
|
|
31
|
+
}
|
|
32
|
+
export function ensureTaskWorkspaceDir(taskKey) {
|
|
33
|
+
return ensureScopeWorkspaceDir(taskKey);
|
|
34
|
+
}
|
|
17
35
|
export function taskWorkspaceFile(taskKey, fileName) {
|
|
18
|
-
return
|
|
36
|
+
return scopeWorkspaceFile(taskKey, fileName);
|
|
19
37
|
}
|
|
20
38
|
export function taskArtifactsDir(taskKey) {
|
|
21
|
-
return
|
|
39
|
+
return scopeArtifactsDir(taskKey);
|
|
22
40
|
}
|
|
23
41
|
export function taskArtifactsFile(taskKey, fileName) {
|
|
24
|
-
return
|
|
42
|
+
return scopeArtifactsFile(taskKey, fileName);
|
|
25
43
|
}
|
|
26
44
|
export function artifactFile(prefix, taskKey, iteration) {
|
|
27
45
|
return taskWorkspaceFile(taskKey, `${prefix}-${taskKey}-${iteration}.md`);
|
|
@@ -101,6 +119,9 @@ export function gitlabReviewInputJsonFile(taskKey) {
|
|
|
101
119
|
export function autoStateFile(taskKey) {
|
|
102
120
|
return taskArtifactsFile(taskKey, `.agentweaver-state-${taskKey}.json`);
|
|
103
121
|
}
|
|
122
|
+
export function flowStateFile(scopeKey, flowId) {
|
|
123
|
+
return scopeArtifactsFile(scopeKey, `.agentweaver-flow-state-${flowId}.json`);
|
|
124
|
+
}
|
|
104
125
|
export function planArtifacts(taskKey) {
|
|
105
126
|
return [designFile(taskKey), designJsonFile(taskKey), planFile(taskKey), planJsonFile(taskKey), qaFile(taskKey), qaJsonFile(taskKey)];
|
|
106
127
|
}
|
|
@@ -135,6 +156,12 @@ export function reviewFixJsonFile(taskKey, iteration) {
|
|
|
135
156
|
export function reviewFixSelectionJsonFile(taskKey, iteration) {
|
|
136
157
|
return artifactJsonFile("review-fix-selection", taskKey, iteration);
|
|
137
158
|
}
|
|
159
|
+
export function runGoLinterResultJsonFile(taskKey, iteration) {
|
|
160
|
+
return artifactJsonFile("run-go-linter-result", taskKey, iteration);
|
|
161
|
+
}
|
|
162
|
+
export function runGoTestsResultJsonFile(taskKey, iteration) {
|
|
163
|
+
return artifactJsonFile("run-go-tests-result", taskKey, iteration);
|
|
164
|
+
}
|
|
138
165
|
export function requireArtifacts(paths, message) {
|
|
139
166
|
const missing = paths.filter((filePath) => !existsSync(filePath));
|
|
140
167
|
if (missing.length > 0) {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { ensureScopeWorkspaceDir, flowStateFile } from "./artifacts.js";
|
|
3
|
+
import { TaskRunnerError } from "./errors.js";
|
|
4
|
+
const FLOW_STATE_SCHEMA_VERSION = 1;
|
|
5
|
+
function nowIso8601() {
|
|
6
|
+
return new Date().toISOString();
|
|
7
|
+
}
|
|
8
|
+
export function stripExecutionStatePayload(executionState) {
|
|
9
|
+
return {
|
|
10
|
+
flowKind: executionState.flowKind,
|
|
11
|
+
flowVersion: executionState.flowVersion,
|
|
12
|
+
terminated: executionState.terminated,
|
|
13
|
+
...(executionState.terminationReason ? { terminationReason: executionState.terminationReason } : {}),
|
|
14
|
+
phases: executionState.phases.map((phase) => ({
|
|
15
|
+
id: phase.id,
|
|
16
|
+
status: phase.status,
|
|
17
|
+
repeatVars: { ...phase.repeatVars },
|
|
18
|
+
...(phase.startedAt ? { startedAt: phase.startedAt } : {}),
|
|
19
|
+
...(phase.finishedAt ? { finishedAt: phase.finishedAt } : {}),
|
|
20
|
+
steps: phase.steps.map((step) => ({
|
|
21
|
+
id: step.id,
|
|
22
|
+
status: step.status,
|
|
23
|
+
...(step.outputs ? { outputs: step.outputs } : {}),
|
|
24
|
+
...(step.value !== undefined ? { value: step.value } : {}),
|
|
25
|
+
...(step.startedAt ? { startedAt: step.startedAt } : {}),
|
|
26
|
+
...(step.finishedAt ? { finishedAt: step.finishedAt } : {}),
|
|
27
|
+
...(step.stopFlow !== undefined ? { stopFlow: step.stopFlow } : {}),
|
|
28
|
+
})),
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function createFlowRunState(scopeKey, flowId, executionState) {
|
|
33
|
+
return {
|
|
34
|
+
schemaVersion: FLOW_STATE_SCHEMA_VERSION,
|
|
35
|
+
flowId,
|
|
36
|
+
scopeKey,
|
|
37
|
+
status: "pending",
|
|
38
|
+
currentStep: null,
|
|
39
|
+
updatedAt: nowIso8601(),
|
|
40
|
+
executionState: stripExecutionStatePayload(executionState),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function loadFlowRunState(scopeKey, flowId) {
|
|
44
|
+
const filePath = flowStateFile(scopeKey, flowId);
|
|
45
|
+
if (!existsSync(filePath)) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
let raw;
|
|
49
|
+
try {
|
|
50
|
+
raw = JSON.parse(readFileSync(filePath, "utf8"));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new TaskRunnerError(`Failed to parse flow state file ${filePath}: ${error.message}`);
|
|
54
|
+
}
|
|
55
|
+
if (!raw || typeof raw !== "object") {
|
|
56
|
+
throw new TaskRunnerError(`Invalid flow state file format: ${filePath}`);
|
|
57
|
+
}
|
|
58
|
+
const state = raw;
|
|
59
|
+
if (state.schemaVersion !== FLOW_STATE_SCHEMA_VERSION) {
|
|
60
|
+
throw new TaskRunnerError(`Unsupported flow state schema in ${filePath}: ${state.schemaVersion}`);
|
|
61
|
+
}
|
|
62
|
+
if (state.flowId !== flowId) {
|
|
63
|
+
throw new TaskRunnerError(`Flow state ${filePath} belongs to flow '${state.flowId}', expected '${flowId}'`);
|
|
64
|
+
}
|
|
65
|
+
return state;
|
|
66
|
+
}
|
|
67
|
+
export function saveFlowRunState(state) {
|
|
68
|
+
state.updatedAt = nowIso8601();
|
|
69
|
+
ensureScopeWorkspaceDir(state.scopeKey);
|
|
70
|
+
writeFileSync(flowStateFile(state.scopeKey, state.flowId), `${JSON.stringify({
|
|
71
|
+
...state,
|
|
72
|
+
executionState: stripExecutionStatePayload(state.executionState),
|
|
73
|
+
}, null, 2)}\n`, "utf8");
|
|
74
|
+
}
|
|
75
|
+
export function resetFlowRunState(scopeKey, flowId) {
|
|
76
|
+
const filePath = flowStateFile(scopeKey, flowId);
|
|
77
|
+
if (!existsSync(filePath)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
rmSync(filePath);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
export function hasResumableFlowState(state) {
|
|
84
|
+
if (!state) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (state.executionState.terminated) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (state.status === "completed") {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (state.status === "running" || state.status === "blocked") {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return state.executionState.phases.some((phase) => phase.steps.some((step) => step.status === "done" || step.status === "running"));
|
|
97
|
+
}
|
|
98
|
+
function normalizeStepState(step) {
|
|
99
|
+
if (step.status !== "running") {
|
|
100
|
+
return step;
|
|
101
|
+
}
|
|
102
|
+
const { finishedAt: _finishedAt, outputs: _outputs, value: _value, stopFlow: _stopFlow, ...rest } = step;
|
|
103
|
+
return {
|
|
104
|
+
...rest,
|
|
105
|
+
status: "pending",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function normalizePhaseState(phase) {
|
|
109
|
+
const normalizedSteps = phase.steps.map(normalizeStepState);
|
|
110
|
+
if (phase.status !== "running") {
|
|
111
|
+
return {
|
|
112
|
+
...phase,
|
|
113
|
+
steps: normalizedSteps,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const { finishedAt: _finishedAt, ...rest } = phase;
|
|
117
|
+
return {
|
|
118
|
+
...rest,
|
|
119
|
+
status: "pending",
|
|
120
|
+
steps: normalizedSteps,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export function prepareFlowStateForResume(state) {
|
|
124
|
+
state.status = "pending";
|
|
125
|
+
state.lastError = null;
|
|
126
|
+
state.currentStep = null;
|
|
127
|
+
state.executionState = {
|
|
128
|
+
...state.executionState,
|
|
129
|
+
terminated: false,
|
|
130
|
+
phases: state.executionState.phases.map(normalizePhaseState),
|
|
131
|
+
};
|
|
132
|
+
delete state.executionState.terminationReason;
|
|
133
|
+
return state;
|
|
134
|
+
}
|