agentweaver 0.1.18 → 0.1.19
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 +8 -0
- package/dist/index.js +6 -2
- package/dist/interactive/controller.js +74 -0
- package/dist/interactive/state.js +9 -0
- package/dist/interactive/web/index.js +149 -2
- package/dist/interactive/web/protocol.js +7 -1
- package/dist/interactive/web/server.js +439 -3
- package/dist/interactive/web/static/app.js +873 -2
- package/dist/interactive/web/static/index.html +37 -0
- package/dist/interactive/web/static/styles.css +1 -1
- package/dist/interactive/web/static/styles.input.css +380 -0
- package/dist/runtime/artifact-catalog.js +379 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,6 +146,14 @@ The Web UI serves the operator console from the same local process, including `/
|
|
|
146
146
|
|
|
147
147
|
Web UI state is process-local: it exists only while the AgentWeaver process is running and is not shared with other AgentWeaver processes. The Web UI is intended to match the interactive operator workflow for flow selection, launch confirmation, routing and user-input forms, progress and logs, and interrupt handling.
|
|
148
148
|
|
|
149
|
+
### Artifact Explorer
|
|
150
|
+
|
|
151
|
+
After a Web UI workflow completes, and also after a failed run when artifacts were written before failure, the Web UI offers the Artifact Explorer. It reads artifacts from the active AgentWeaver scope only, optionally filtered to the run id published by the completed workflow. The browser requests artifact content through safe artifact identifiers resolved by the active catalog and registry; it does not accept arbitrary filesystem paths.
|
|
152
|
+
|
|
153
|
+
The MVP explorer previews Markdown, JSON, plain text, and diff artifacts. Diffs are rendered as text. Binary and unknown artifacts are listed with metadata and safe raw/download actions, but their inline preview is a placeholder. Large previews are bounded and marked as truncated with loaded byte and total size metadata; raw and download links can still serve the full artifact bytes with no-store cache headers and safe content types.
|
|
154
|
+
|
|
155
|
+
When Web UI credentials are configured, the same HTTP Basic auth protection applies to `/`, `/static/*`, `/__agentweaver/ws`, `/__agentweaver/exit`, and the artifact list, preview, raw, and download API routes. The MVP explorer does not support artifact editing, comments, run comparison, image previews, specialized viewers, live updates, or full-text search.
|
|
156
|
+
|
|
149
157
|
## Installation
|
|
150
158
|
|
|
151
159
|
Local development:
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ import { requestUserInputInTerminal } from "./user-input.js";
|
|
|
38
38
|
import { runDoctorCommand } from "./doctor/index.js";
|
|
39
39
|
import { requestJiraContext, resolveProjectScope, } from "./scope.js";
|
|
40
40
|
const COMMANDS = [
|
|
41
|
+
"auto",
|
|
41
42
|
"auto-golang",
|
|
42
43
|
"auto-common-guided",
|
|
43
44
|
"auto-common",
|
|
@@ -174,6 +175,8 @@ function usage() {
|
|
|
174
175
|
agentweaver review-loop [--dry] [--verbose] [--prompt <text>] [--scope <name>] [--blocking-severities <list>] [<jira-browse-url|jira-issue-key>]
|
|
175
176
|
agentweaver run-go-tests-loop [--dry] [--verbose] [--prompt <text>] [--scope <name>] [<jira-browse-url|jira-issue-key>]
|
|
176
177
|
agentweaver run-go-linter-loop [--dry] [--verbose] [--prompt <text>] [--scope <name>] [<jira-browse-url|jira-issue-key>]
|
|
178
|
+
agentweaver auto [--dry] [--verbose] [--prompt <text>] [--md-lang <en|ru>] <jira-browse-url|jira-issue-key>
|
|
179
|
+
agentweaver auto --help-phases
|
|
177
180
|
agentweaver auto-golang [--dry] [--verbose] [--prompt <text>] [<jira-browse-url|jira-issue-key>]
|
|
178
181
|
agentweaver auto-golang [--dry] [--verbose] [--prompt <text>] --from <phase> [<jira-browse-url|jira-issue-key>]
|
|
179
182
|
agentweaver auto-golang --help-phases
|
|
@@ -1481,11 +1484,12 @@ async function parseCliArgs(argv) {
|
|
|
1481
1484
|
writeStderrSync(`${usage()}\n`);
|
|
1482
1485
|
process.exit(1);
|
|
1483
1486
|
}
|
|
1484
|
-
const
|
|
1485
|
-
if (!COMMANDS.includes(
|
|
1487
|
+
const rawCommand = argv[0];
|
|
1488
|
+
if (!COMMANDS.includes(rawCommand)) {
|
|
1486
1489
|
writeStderrSync(`${usage()}\n`);
|
|
1487
1490
|
process.exit(1);
|
|
1488
1491
|
}
|
|
1492
|
+
const command = rawCommand === "auto" ? "auto-common" : rawCommand;
|
|
1489
1493
|
let dry = false;
|
|
1490
1494
|
let verbose = false;
|
|
1491
1495
|
let prompt;
|
|
@@ -522,6 +522,79 @@ export class InteractiveSessionController {
|
|
|
522
522
|
setScrollOffset(panel, offset) {
|
|
523
523
|
this.applyScrollOffset(panel, offset, this.panelMaxScroll(panel));
|
|
524
524
|
}
|
|
525
|
+
getCurrentFlowExecutionState() {
|
|
526
|
+
return this.state.flowState.executionState;
|
|
527
|
+
}
|
|
528
|
+
hasActiveInput() {
|
|
529
|
+
return this.confirmSession !== null || this.activeFormSession !== null;
|
|
530
|
+
}
|
|
531
|
+
setArtifactExplorerAvailability(input) {
|
|
532
|
+
const count = input.artifactCount;
|
|
533
|
+
const hasCount = typeof count === "number";
|
|
534
|
+
const failed = input.status === "failed";
|
|
535
|
+
const label = input.label
|
|
536
|
+
?? (failed
|
|
537
|
+
? hasCount && count > 0 ? "Run failed; artifacts available" : "Run failed"
|
|
538
|
+
: hasCount && count === 0 ? "Run completed; no artifacts found" : "Artifacts ready");
|
|
539
|
+
const message = input.message
|
|
540
|
+
?? (failed
|
|
541
|
+
? hasCount && count > 0
|
|
542
|
+
? "The workflow failed, but artifacts are available for review."
|
|
543
|
+
: "The workflow failed. The explorer can check for any artifacts written before failure."
|
|
544
|
+
: hasCount && count === 0
|
|
545
|
+
? "The workflow completed, but no artifacts were found for this run yet."
|
|
546
|
+
: "The workflow completed and artifacts are available for review.");
|
|
547
|
+
this.state.artifactExplorer = {
|
|
548
|
+
available: true,
|
|
549
|
+
open: Boolean(input.open) && !this.hasActiveInput(),
|
|
550
|
+
scopeKey: input.scopeKey,
|
|
551
|
+
runId: input.runId ?? null,
|
|
552
|
+
...(input.runIds && input.runIds.length > 1 ? { runIds: input.runIds } : {}),
|
|
553
|
+
status: input.status,
|
|
554
|
+
label,
|
|
555
|
+
...(hasCount ? { artifactCount: count } : {}),
|
|
556
|
+
message,
|
|
557
|
+
};
|
|
558
|
+
this.emitChange();
|
|
559
|
+
}
|
|
560
|
+
setArtifactExplorerUnavailable(message = "Artifacts are available after a Web UI workflow run completes.") {
|
|
561
|
+
if (!this.state.artifactExplorer.available && !this.state.artifactExplorer.open) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
this.state.artifactExplorer = {
|
|
565
|
+
available: false,
|
|
566
|
+
open: false,
|
|
567
|
+
scopeKey: null,
|
|
568
|
+
runId: null,
|
|
569
|
+
status: "unavailable",
|
|
570
|
+
label: "Artifact Explorer",
|
|
571
|
+
message,
|
|
572
|
+
};
|
|
573
|
+
this.emitChange();
|
|
574
|
+
}
|
|
575
|
+
closeArtifactExplorer() {
|
|
576
|
+
if (!this.state.artifactExplorer.open) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
this.state.artifactExplorer = {
|
|
580
|
+
...this.state.artifactExplorer,
|
|
581
|
+
open: false,
|
|
582
|
+
};
|
|
583
|
+
this.emitChange();
|
|
584
|
+
}
|
|
585
|
+
openArtifactExplorer() {
|
|
586
|
+
if (!this.state.artifactExplorer.available || this.hasActiveInput()) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (this.state.artifactExplorer.open) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
this.state.artifactExplorer = {
|
|
593
|
+
...this.state.artifactExplorer,
|
|
594
|
+
open: true,
|
|
595
|
+
};
|
|
596
|
+
this.emitChange();
|
|
597
|
+
}
|
|
525
598
|
getViewModel(layout) {
|
|
526
599
|
const selectedItem = this.selectedFlowTreeItem();
|
|
527
600
|
const activeFlowId = this.activeFlowId();
|
|
@@ -566,6 +639,7 @@ export class InteractiveSessionController {
|
|
|
566
639
|
confirmText: this.renderConfirmText(),
|
|
567
640
|
confirmation: this.renderConfirmationView(),
|
|
568
641
|
form: this.renderFormView(layout),
|
|
642
|
+
artifactExplorer: { ...this.state.artifactExplorer },
|
|
569
643
|
};
|
|
570
644
|
}
|
|
571
645
|
emitChange(event = { type: "render" }) {
|
|
@@ -31,5 +31,14 @@ export function createInitialInteractiveState(options) {
|
|
|
31
31
|
summaryScrollOffset: 0,
|
|
32
32
|
logScrollOffset: 0,
|
|
33
33
|
helpScrollOffset: 0,
|
|
34
|
+
artifactExplorer: {
|
|
35
|
+
available: false,
|
|
36
|
+
open: false,
|
|
37
|
+
scopeKey: null,
|
|
38
|
+
runId: null,
|
|
39
|
+
status: "unavailable",
|
|
40
|
+
label: "Artifact Explorer",
|
|
41
|
+
message: "Artifacts are available after a Web UI workflow run completes.",
|
|
42
|
+
},
|
|
34
43
|
};
|
|
35
44
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { writeSync } from "node:fs";
|
|
3
3
|
import { FlowInterruptedError } from "../../errors.js";
|
|
4
|
+
import { listArtifactCatalog } from "../../runtime/artifact-catalog.js";
|
|
5
|
+
import { createArtifactRegistry } from "../../runtime/artifact-registry.js";
|
|
4
6
|
import { InteractiveSessionController } from "../controller.js";
|
|
5
|
-
import { startWebServer } from "./server.js";
|
|
7
|
+
import { startWebServer, } from "./server.js";
|
|
6
8
|
function actionId(action) {
|
|
7
9
|
return "actionId" in action ? action.actionId : undefined;
|
|
8
10
|
}
|
|
@@ -12,6 +14,17 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
12
14
|
let unsubscribe = null;
|
|
13
15
|
let mounted = false;
|
|
14
16
|
let shuttingDown = false;
|
|
17
|
+
let activeScopeKey = options.scopeKey;
|
|
18
|
+
let artifactRestoreGeneration = 0;
|
|
19
|
+
const artifactCatalogProvider = webOptions.getArtifactCatalog ?? ((input) => {
|
|
20
|
+
const explorerScopeKey = controller.getViewModel().artifactExplorer.scopeKey;
|
|
21
|
+
const requestedScopeKey = input?.scopeKey;
|
|
22
|
+
const scopeKey = requestedScopeKey && requestedScopeKey === explorerScopeKey ? requestedScopeKey : activeScopeKey;
|
|
23
|
+
return listArtifactCatalog({
|
|
24
|
+
scopeKey,
|
|
25
|
+
artifactRegistry: createArtifactRegistry(),
|
|
26
|
+
});
|
|
27
|
+
});
|
|
15
28
|
function snapshot() {
|
|
16
29
|
return { type: "snapshot", viewModel: controller.getViewModel() };
|
|
17
30
|
}
|
|
@@ -24,7 +37,117 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
24
37
|
server?.broadcast(event);
|
|
25
38
|
}
|
|
26
39
|
}
|
|
40
|
+
function uniqueStrings(values) {
|
|
41
|
+
return values.filter((value, index, allValues) => (typeof value === "string" && value.length > 0 && allValues.indexOf(value) === index));
|
|
42
|
+
}
|
|
43
|
+
function collectPublishedArtifactRunIds(executionState) {
|
|
44
|
+
const runIds = [];
|
|
45
|
+
for (const phase of executionState?.phases ?? []) {
|
|
46
|
+
for (const step of phase.steps) {
|
|
47
|
+
for (const artifact of step.publishedArtifacts ?? []) {
|
|
48
|
+
const runId = artifact.manifest?.run_id;
|
|
49
|
+
if (runId) {
|
|
50
|
+
runIds.push(runId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return uniqueStrings(runIds);
|
|
56
|
+
}
|
|
57
|
+
function candidateRunIds() {
|
|
58
|
+
const executionState = controller.getCurrentFlowExecutionState();
|
|
59
|
+
return uniqueStrings([
|
|
60
|
+
executionState?.runId ?? null,
|
|
61
|
+
executionState?.publicationRunId ?? null,
|
|
62
|
+
...collectPublishedArtifactRunIds(executionState),
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
async function resolveArtifactExplorerRunMetadata(scopeKey) {
|
|
66
|
+
const candidates = candidateRunIds();
|
|
67
|
+
const preferredRunId = candidates[0] ?? null;
|
|
68
|
+
try {
|
|
69
|
+
const catalog = await artifactCatalogProvider({
|
|
70
|
+
scopeKey,
|
|
71
|
+
...(candidates.length === 1 && preferredRunId ? { runId: preferredRunId, runIds: candidates } : {}),
|
|
72
|
+
...(candidates.length > 1 ? { runIds: candidates } : {}),
|
|
73
|
+
});
|
|
74
|
+
if (!catalog || catalog.scopeKey !== scopeKey) {
|
|
75
|
+
return { runId: preferredRunId };
|
|
76
|
+
}
|
|
77
|
+
if (candidates.length === 0) {
|
|
78
|
+
return {
|
|
79
|
+
runId: null,
|
|
80
|
+
artifactCount: catalog.items.filter((item) => item.scopeKey === scopeKey && item.kind === "markdown").length,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const matchingRunIds = candidates.filter((candidate) => (catalog.items.some((item) => item.scopeKey === scopeKey && item.runId === candidate && item.kind === "markdown")));
|
|
84
|
+
if (matchingRunIds.length > 0) {
|
|
85
|
+
const matchingRunIdSet = new Set(matchingRunIds);
|
|
86
|
+
return {
|
|
87
|
+
runId: matchingRunIds[0] ?? preferredRunId,
|
|
88
|
+
...(matchingRunIds.length > 1 ? { runIds: matchingRunIds } : {}),
|
|
89
|
+
artifactCount: catalog.items.filter((item) => (item.scopeKey === scopeKey
|
|
90
|
+
&& item.kind === "markdown"
|
|
91
|
+
&& item.runId !== null
|
|
92
|
+
&& matchingRunIdSet.has(item.runId))).length,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
runId: preferredRunId,
|
|
97
|
+
artifactCount: catalog.items.filter((item) => item.scopeKey === scopeKey && item.kind === "markdown" && item.runId === preferredRunId).length,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return { runId: preferredRunId };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function markArtifactExplorerForCompletedRun(status) {
|
|
105
|
+
artifactRestoreGeneration += 1;
|
|
106
|
+
const scopeKey = activeScopeKey;
|
|
107
|
+
const { runId, runIds, artifactCount } = await resolveArtifactExplorerRunMetadata(scopeKey);
|
|
108
|
+
controller.setArtifactExplorerAvailability({
|
|
109
|
+
scopeKey,
|
|
110
|
+
runId,
|
|
111
|
+
...(runIds ? { runIds } : {}),
|
|
112
|
+
status,
|
|
113
|
+
...(artifactCount !== undefined ? { artifactCount } : {}),
|
|
114
|
+
open: !controller.hasActiveInput(),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async function restoreArtifactExplorerFromScope(scopeKey) {
|
|
118
|
+
const generation = ++artifactRestoreGeneration;
|
|
119
|
+
try {
|
|
120
|
+
const catalog = await artifactCatalogProvider({ scopeKey });
|
|
121
|
+
if (generation !== artifactRestoreGeneration || shuttingDown || activeScopeKey !== scopeKey) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!catalog || catalog.scopeKey !== scopeKey) {
|
|
125
|
+
controller.setArtifactExplorerUnavailable();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const artifactCount = catalog.items.filter((item) => item.scopeKey === scopeKey && item.kind === "markdown").length;
|
|
129
|
+
if (artifactCount === 0) {
|
|
130
|
+
controller.setArtifactExplorerUnavailable("No markdown artifacts were found for the current scope.");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
controller.setArtifactExplorerAvailability({
|
|
134
|
+
scopeKey,
|
|
135
|
+
runId: null,
|
|
136
|
+
status: "completed",
|
|
137
|
+
artifactCount,
|
|
138
|
+
open: false,
|
|
139
|
+
label: "Artifacts available",
|
|
140
|
+
message: "Markdown artifacts from this scope are available for review.",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
if (generation === artifactRestoreGeneration && !shuttingDown && activeScopeKey === scopeKey) {
|
|
145
|
+
controller.setArtifactExplorerUnavailable("Artifact Explorer could not inspect the current scope.");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
27
149
|
async function dispatch(action, client) {
|
|
150
|
+
let acceptedRunConfirmation = false;
|
|
28
151
|
try {
|
|
29
152
|
if (action.type === "flow.select") {
|
|
30
153
|
if (action.key) {
|
|
@@ -48,10 +171,16 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
48
171
|
return;
|
|
49
172
|
}
|
|
50
173
|
if (action.type === "confirm.accept") {
|
|
174
|
+
const confirmation = controller.getViewModel().confirmation;
|
|
175
|
+
const acceptedAction = action.action ?? confirmation?.selectedAction;
|
|
176
|
+
acceptedRunConfirmation = confirmation?.kind === "run" && acceptedAction !== "cancel";
|
|
51
177
|
if (action.action) {
|
|
52
178
|
controller.selectConfirmAction(action.action);
|
|
53
179
|
}
|
|
54
180
|
await controller.acceptConfirmation();
|
|
181
|
+
if (acceptedRunConfirmation) {
|
|
182
|
+
await markArtifactExplorerForCompletedRun("completed");
|
|
183
|
+
}
|
|
55
184
|
return;
|
|
56
185
|
}
|
|
57
186
|
if (action.type === "confirm.cancel") {
|
|
@@ -86,6 +215,14 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
86
215
|
controller.clearLog();
|
|
87
216
|
return;
|
|
88
217
|
}
|
|
218
|
+
if (action.type === "artifactExplorer.open") {
|
|
219
|
+
controller.openArtifactExplorer();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (action.type === "artifactExplorer.close") {
|
|
223
|
+
controller.closeArtifactExplorer();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
89
226
|
if (action.type === "help.toggle") {
|
|
90
227
|
controller.showHelp(action.visible ?? !controller.getViewModel().helpVisible);
|
|
91
228
|
return;
|
|
@@ -93,6 +230,9 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
93
230
|
controller.scrollPane(action.pane, { ...(action.delta !== undefined ? { delta: action.delta } : {}), ...(action.offset !== undefined ? { offset: action.offset } : {}) });
|
|
94
231
|
}
|
|
95
232
|
catch (error) {
|
|
233
|
+
if (acceptedRunConfirmation) {
|
|
234
|
+
await markArtifactExplorerForCompletedRun("failed");
|
|
235
|
+
}
|
|
96
236
|
const message = error.message;
|
|
97
237
|
controller.appendLog(`Web action failed: ${message}`);
|
|
98
238
|
sendError(client, message, actionId(action));
|
|
@@ -105,6 +245,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
105
245
|
}
|
|
106
246
|
mounted = true;
|
|
107
247
|
controller.mount();
|
|
248
|
+
void restoreArtifactExplorerFromScope(activeScopeKey);
|
|
108
249
|
unsubscribe = controller.subscribe((event) => {
|
|
109
250
|
if (event.type === "log") {
|
|
110
251
|
server?.broadcast({ type: "log.append", appendedLines: event.appendedLines });
|
|
@@ -121,6 +262,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
121
262
|
controller.appendLog(message);
|
|
122
263
|
},
|
|
123
264
|
...(webOptions.openBrowser ? { openBrowser: webOptions.openBrowser } : {}),
|
|
265
|
+
getArtifactCatalog: (input) => artifactCatalogProvider(input),
|
|
124
266
|
onClientAction: (action, client) => {
|
|
125
267
|
void dispatch(action, client);
|
|
126
268
|
},
|
|
@@ -166,7 +308,12 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
166
308
|
requestUserInput: (form) => controller.requestUserInput(form),
|
|
167
309
|
setSummary: (markdown) => controller.setSummary(markdown),
|
|
168
310
|
clearSummary: () => controller.clearSummary(),
|
|
169
|
-
setScope: (scopeKey, jiraIssueKey, gitBranchName) =>
|
|
311
|
+
setScope: (scopeKey, jiraIssueKey, gitBranchName) => {
|
|
312
|
+
activeScopeKey = scopeKey;
|
|
313
|
+
controller.setScope(scopeKey, jiraIssueKey, gitBranchName);
|
|
314
|
+
controller.setArtifactExplorerUnavailable();
|
|
315
|
+
void restoreArtifactExplorerFromScope(scopeKey);
|
|
316
|
+
},
|
|
170
317
|
appendLog: (text) => controller.appendLog(text),
|
|
171
318
|
setFlowFailed: (flowId) => controller.setFlowFailed(flowId),
|
|
172
319
|
interruptActiveForm: (message = "Flow interrupted by user.") => {
|
|
@@ -12,6 +12,8 @@ const ACTION_TYPES = new Set([
|
|
|
12
12
|
"interrupt.openConfirm",
|
|
13
13
|
"flow.interrupt",
|
|
14
14
|
"log.clear",
|
|
15
|
+
"artifactExplorer.open",
|
|
16
|
+
"artifactExplorer.close",
|
|
15
17
|
"help.toggle",
|
|
16
18
|
"scroll",
|
|
17
19
|
]);
|
|
@@ -96,7 +98,11 @@ export function parseClientAction(raw) {
|
|
|
96
98
|
const action = optionalNonEmptyString(parsed, "action");
|
|
97
99
|
return { type: "confirm.accept", ...(action ? { action } : {}), ...(actionId ? { actionId } : {}) };
|
|
98
100
|
}
|
|
99
|
-
if (parsed.type === "confirm.cancel"
|
|
101
|
+
if (parsed.type === "confirm.cancel"
|
|
102
|
+
|| parsed.type === "form.cancel"
|
|
103
|
+
|| parsed.type === "log.clear"
|
|
104
|
+
|| parsed.type === "artifactExplorer.open"
|
|
105
|
+
|| parsed.type === "artifactExplorer.close") {
|
|
100
106
|
return { type: parsed.type, ...(actionId ? { actionId } : {}) };
|
|
101
107
|
}
|
|
102
108
|
if (parsed.type === "form.update") {
|