agentweaver 0.1.19 → 0.1.20
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 +47 -7
- package/dist/artifacts.js +9 -0
- package/dist/executors/git-commit-executor.js +24 -6
- package/dist/flow-state.js +3 -8
- package/dist/git/git-diff-parser.js +223 -0
- package/dist/git/git-service.js +562 -0
- package/dist/git/git-stage-selection.js +24 -0
- package/dist/git/git-status-parser.js +171 -0
- package/dist/git/git-types.js +1 -0
- package/dist/index.js +450 -108
- package/dist/interactive/auto-flow.js +644 -0
- package/dist/interactive/controller.js +417 -9
- package/dist/interactive/progress.js +194 -1
- package/dist/interactive/state.js +25 -0
- package/dist/interactive/web/index.js +97 -12
- package/dist/interactive/web/protocol.js +216 -1
- package/dist/interactive/web/server.js +72 -14
- package/dist/interactive/web/static/app.js +1603 -49
- package/dist/interactive/web/static/index.html +76 -11
- package/dist/interactive/web/static/styles.css +1 -1
- package/dist/interactive/web/static/styles.input.css +901 -47
- package/dist/pipeline/auto-flow-blocks.js +307 -0
- package/dist/pipeline/auto-flow-config.js +273 -0
- package/dist/pipeline/auto-flow-identity.js +49 -0
- package/dist/pipeline/auto-flow-presets.js +52 -0
- package/dist/pipeline/auto-flow-resolver.js +830 -0
- package/dist/pipeline/auto-flow-types.js +17 -0
- package/dist/pipeline/context.js +1 -0
- package/dist/pipeline/declarative-flows.js +27 -1
- package/dist/pipeline/flow-specs/auto-common-guided.json +11 -0
- package/dist/pipeline/flow-specs/auto-golang.json +12 -1
- package/dist/pipeline/flow-specs/bugz/bug-analyze.json +54 -1
- package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +19 -1
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +33 -1
- package/dist/pipeline/flow-specs/review/review-project.json +19 -1
- package/dist/pipeline/flow-specs/task-source/manual-jira-input.json +70 -0
- package/dist/pipeline/node-registry.js +9 -0
- package/dist/pipeline/nodes/codex-prompt-node.js +8 -1
- package/dist/pipeline/nodes/flow-run-node.js +5 -3
- package/dist/pipeline/nodes/git-status-node.js +2 -168
- package/dist/pipeline/nodes/manual-jira-task-input-node.js +146 -0
- package/dist/pipeline/nodes/opencode-prompt-node.js +8 -1
- package/dist/pipeline/nodes/plan-codex-node.js +8 -1
- package/dist/pipeline/spec-loader.js +14 -4
- package/dist/runtime/artifact-catalog.js +29 -5
- package/dist/runtime/settings.js +114 -0
- package/dist/scope.js +14 -4
- package/package.json +1 -1
- package/dist/pipeline/flow-specs/auto-common.json +0 -179
- package/dist/pipeline/flow-specs/auto-simple.json +0 -141
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildAutoFlowEditorViewModel } from "./auto-flow.js";
|
|
1
2
|
export function displayPhaseId(phase) {
|
|
2
3
|
let result = phase.id;
|
|
3
4
|
const values = Object.entries(phase.repeatVars)
|
|
@@ -139,7 +140,7 @@ export function visiblePhaseItems(flow, flowState) {
|
|
|
139
140
|
return true;
|
|
140
141
|
});
|
|
141
142
|
}
|
|
142
|
-
export function buildProgressViewModel(flow, flowState) {
|
|
143
|
+
export function buildProgressViewModel(flow, flowState, options = {}) {
|
|
143
144
|
if (!flow) {
|
|
144
145
|
return {
|
|
145
146
|
flow: null,
|
|
@@ -147,6 +148,9 @@ export function buildProgressViewModel(flow, flowState) {
|
|
|
147
148
|
anchorIndex: null,
|
|
148
149
|
};
|
|
149
150
|
}
|
|
151
|
+
if (flow.autoFlow) {
|
|
152
|
+
return buildAutoFlowProgressViewModel(flow, flowState, options);
|
|
153
|
+
}
|
|
150
154
|
const items = [];
|
|
151
155
|
let anchorIndex = null;
|
|
152
156
|
let sawExecutedItem = false;
|
|
@@ -243,3 +247,192 @@ export function buildProgressViewModel(flow, flowState) {
|
|
|
243
247
|
anchorIndex,
|
|
244
248
|
};
|
|
245
249
|
}
|
|
250
|
+
function phaseOrder(flow) {
|
|
251
|
+
return new Map(flow.phases.map((phase, index) => [phase.id, index]));
|
|
252
|
+
}
|
|
253
|
+
function stoppedPhaseId(flowState) {
|
|
254
|
+
const terminationReason = flowState?.terminationReason ?? "";
|
|
255
|
+
const match = /^Stopped by ([^:]+):/.exec(terminationReason);
|
|
256
|
+
return match?.[1] ?? null;
|
|
257
|
+
}
|
|
258
|
+
function mapRuntimeStatus(status) {
|
|
259
|
+
if (status === "done") {
|
|
260
|
+
return "success";
|
|
261
|
+
}
|
|
262
|
+
return status;
|
|
263
|
+
}
|
|
264
|
+
function lastRuntimeBlockId(slots, flow, flowState) {
|
|
265
|
+
const order = phaseOrder(flow);
|
|
266
|
+
let result = null;
|
|
267
|
+
for (const slot of slots) {
|
|
268
|
+
for (const block of slot.blocks) {
|
|
269
|
+
if (!block.phaseId) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const phaseState = flowState?.phases.find((phase) => phase.id === block.phaseId);
|
|
273
|
+
if (!phaseState || phaseState.status === "pending" || phaseState.status === "skipped") {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const phaseIndex = order.get(block.phaseId) ?? -1;
|
|
277
|
+
if (!result || phaseIndex >= result.phaseIndex) {
|
|
278
|
+
result = { blockId: block.blockId, phaseIndex };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return result?.blockId ?? null;
|
|
283
|
+
}
|
|
284
|
+
function runtimeStatusForBlock(block, input) {
|
|
285
|
+
if (block.status === "invalid" || block.status === "disabled" || block.status === "blocked" || block.status === "empty") {
|
|
286
|
+
return block.status;
|
|
287
|
+
}
|
|
288
|
+
if (!block.phaseId) {
|
|
289
|
+
return block.status;
|
|
290
|
+
}
|
|
291
|
+
const phaseState = input.flowState?.phases.find((phase) => phase.id === block.phaseId) ?? null;
|
|
292
|
+
const failed = input.failedFlowId === input.flow.id;
|
|
293
|
+
if (failed && (phaseState?.status === "running" || input.fallbackFailedBlockId === block.blockId)) {
|
|
294
|
+
return "failed";
|
|
295
|
+
}
|
|
296
|
+
if (input.waitingForUserInput && phaseState?.status === "running") {
|
|
297
|
+
return "waiting-user";
|
|
298
|
+
}
|
|
299
|
+
const stoppedId = input.flowState?.terminationOutcome === "stopped" ? stoppedPhaseId(input.flowState) : null;
|
|
300
|
+
if (stoppedId && stoppedId === block.phaseId) {
|
|
301
|
+
return "stopped";
|
|
302
|
+
}
|
|
303
|
+
if (phaseState) {
|
|
304
|
+
return mapRuntimeStatus(phaseState.status);
|
|
305
|
+
}
|
|
306
|
+
if (input.flowState?.terminated && stoppedId) {
|
|
307
|
+
const order = phaseOrder(input.flow);
|
|
308
|
+
const stoppedIndex = order.get(stoppedId) ?? -1;
|
|
309
|
+
const currentIndex = order.get(block.phaseId) ?? -1;
|
|
310
|
+
if (stoppedIndex >= 0 && currentIndex > stoppedIndex) {
|
|
311
|
+
return "skipped";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return block.status;
|
|
315
|
+
}
|
|
316
|
+
function aggregateSlotStatus(slot, blockStatuses) {
|
|
317
|
+
if (slot.status === "invalid" || blockStatuses.some((status) => status === "invalid")) {
|
|
318
|
+
return "invalid";
|
|
319
|
+
}
|
|
320
|
+
if (slot.blocks.length === 0) {
|
|
321
|
+
return "empty";
|
|
322
|
+
}
|
|
323
|
+
for (const status of ["failed", "stopped", "waiting-user", "running"]) {
|
|
324
|
+
if (blockStatuses.includes(status)) {
|
|
325
|
+
return status;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (blockStatuses.every((status) => status === "disabled")) {
|
|
329
|
+
return "disabled";
|
|
330
|
+
}
|
|
331
|
+
const executableStatuses = blockStatuses.filter((status) => status !== "disabled");
|
|
332
|
+
if (executableStatuses.length > 0 && executableStatuses.every((status) => status === "success" || status === "skipped")) {
|
|
333
|
+
return executableStatuses.every((status) => status === "skipped") ? "skipped" : "success";
|
|
334
|
+
}
|
|
335
|
+
if (blockStatuses.some((status) => status === "blocked")) {
|
|
336
|
+
return "blocked";
|
|
337
|
+
}
|
|
338
|
+
return "pending";
|
|
339
|
+
}
|
|
340
|
+
function rememberProgressAnchor(items, status, state) {
|
|
341
|
+
if (status === "running" || status === "waiting-user" || status === "failed" || status === "stopped" || status === "invalid") {
|
|
342
|
+
state.anchorIndex = items.length;
|
|
343
|
+
state.sawExecutedItem = true;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (status === "done" || status === "success" || status === "skipped" || status === "disabled") {
|
|
347
|
+
state.sawExecutedItem = true;
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (status === "pending" && state.sawExecutedItem && state.anchorIndex === null) {
|
|
351
|
+
state.anchorIndex = items.length;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function buildAutoFlowProgressViewModel(flow, flowState, options) {
|
|
355
|
+
if (!flow.autoFlow) {
|
|
356
|
+
return {
|
|
357
|
+
flow,
|
|
358
|
+
items: [],
|
|
359
|
+
anchorIndex: null,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
const editor = buildAutoFlowEditorViewModel(flow.autoFlow, {
|
|
363
|
+
...(flow.autoFlow.diagnostics && flow.autoFlow.diagnostics.length > 0 ? { diagnostics: flow.autoFlow.diagnostics } : {}),
|
|
364
|
+
...(flow.autoFlow.lastMessage ? { lastMessage: flow.autoFlow.lastMessage } : {}),
|
|
365
|
+
});
|
|
366
|
+
const items = [];
|
|
367
|
+
const anchorState = { anchorIndex: null, sawExecutedItem: false };
|
|
368
|
+
const fallbackFailedBlockId = options.failedFlowId === flow.id
|
|
369
|
+
? lastRuntimeBlockId(editor.slots, flow, flowState)
|
|
370
|
+
: null;
|
|
371
|
+
for (const slot of editor.slots) {
|
|
372
|
+
const blockRows = slot.blocks.map((block) => ({
|
|
373
|
+
block,
|
|
374
|
+
status: runtimeStatusForBlock(block, {
|
|
375
|
+
flow,
|
|
376
|
+
flowState,
|
|
377
|
+
...(options.failedFlowId !== undefined ? { failedFlowId: options.failedFlowId } : {}),
|
|
378
|
+
...(options.waitingForUserInput !== undefined ? { waitingForUserInput: options.waitingForUserInput } : {}),
|
|
379
|
+
fallbackFailedBlockId,
|
|
380
|
+
}),
|
|
381
|
+
}));
|
|
382
|
+
const status = aggregateSlotStatus(slot, blockRows.map((row) => row.status));
|
|
383
|
+
rememberProgressAnchor(items, status, anchorState);
|
|
384
|
+
items.push({
|
|
385
|
+
kind: "slot",
|
|
386
|
+
label: slot.title,
|
|
387
|
+
depth: 0,
|
|
388
|
+
status,
|
|
389
|
+
detail: slot.reason,
|
|
390
|
+
slotId: slot.slotId,
|
|
391
|
+
});
|
|
392
|
+
for (const { block, status: blockRuntimeStatus } of blockRows) {
|
|
393
|
+
rememberProgressAnchor(items, blockRuntimeStatus, anchorState);
|
|
394
|
+
items.push({
|
|
395
|
+
kind: "block",
|
|
396
|
+
label: block.title,
|
|
397
|
+
depth: 1,
|
|
398
|
+
status: blockRuntimeStatus,
|
|
399
|
+
detail: block.reason,
|
|
400
|
+
slotId: block.slotId,
|
|
401
|
+
blockId: block.blockId,
|
|
402
|
+
locked: block.locked,
|
|
403
|
+
enabled: block.enabled,
|
|
404
|
+
});
|
|
405
|
+
for (const diagnostic of block.diagnostics) {
|
|
406
|
+
rememberProgressAnchor(items, "invalid", anchorState);
|
|
407
|
+
const detail = diagnostic.paramName ? `${diagnostic.blockId ?? "flow"}.${diagnostic.paramName}` : diagnostic.blockId;
|
|
408
|
+
items.push({
|
|
409
|
+
kind: "block",
|
|
410
|
+
label: diagnostic.message,
|
|
411
|
+
depth: 2,
|
|
412
|
+
status: "invalid",
|
|
413
|
+
...(detail ? { detail } : {}),
|
|
414
|
+
slotId: block.slotId,
|
|
415
|
+
blockId: block.blockId,
|
|
416
|
+
locked: block.locked,
|
|
417
|
+
enabled: block.enabled,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (flowState?.terminated) {
|
|
423
|
+
const terminationOutcome = flowState.terminationOutcome ?? "success";
|
|
424
|
+
const status = terminationOutcome === "stopped" ? "stopped" : "success";
|
|
425
|
+
items.push({
|
|
426
|
+
kind: "termination",
|
|
427
|
+
label: terminationOutcome === "stopped" ? "Flow stopped before completion" : "Flow completed successfully",
|
|
428
|
+
detail: `Reason: ${flowState.terminationReason ?? "flow terminated"}`,
|
|
429
|
+
depth: 0,
|
|
430
|
+
status,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
flow,
|
|
435
|
+
items,
|
|
436
|
+
anchorIndex: anchorState.anchorIndex,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
import { buildFlowTree, collectInitiallyExpandedFolderKeys, computeVisibleFlowItems, makeFlowKey } from "./tree.js";
|
|
2
|
+
export function createUnavailableGitWorkspace(message = "Git workspace has not been refreshed yet.") {
|
|
3
|
+
return {
|
|
4
|
+
available: false,
|
|
5
|
+
repositoryRoot: null,
|
|
6
|
+
branch: null,
|
|
7
|
+
detachedHead: false,
|
|
8
|
+
clean: true,
|
|
9
|
+
upstream: null,
|
|
10
|
+
ahead: 0,
|
|
11
|
+
behind: 0,
|
|
12
|
+
lastCommit: null,
|
|
13
|
+
changedFiles: [],
|
|
14
|
+
branches: [],
|
|
15
|
+
remotes: [],
|
|
16
|
+
canPush: false,
|
|
17
|
+
pushDisabledReason: "Git repository is not available.",
|
|
18
|
+
warnings: [],
|
|
19
|
+
error: message,
|
|
20
|
+
refreshedAt: null,
|
|
21
|
+
selectedPaths: [],
|
|
22
|
+
commitMessage: "",
|
|
23
|
+
operation: { status: "idle" },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
2
26
|
export function createInitialInteractiveState(options) {
|
|
3
27
|
const flowTree = buildFlowTree(options.flows);
|
|
4
28
|
const expandedFlowFolders = new Set(collectInitiallyExpandedFolderKeys(flowTree));
|
|
@@ -40,5 +64,6 @@ export function createInitialInteractiveState(options) {
|
|
|
40
64
|
label: "Artifact Explorer",
|
|
41
65
|
message: "Artifacts are available after a Web UI workflow run completes.",
|
|
42
66
|
},
|
|
67
|
+
gitWorkspace: createUnavailableGitWorkspace(),
|
|
43
68
|
};
|
|
44
69
|
}
|
|
@@ -3,6 +3,7 @@ import { writeSync } from "node:fs";
|
|
|
3
3
|
import { FlowInterruptedError } from "../../errors.js";
|
|
4
4
|
import { listArtifactCatalog } from "../../runtime/artifact-catalog.js";
|
|
5
5
|
import { createArtifactRegistry } from "../../runtime/artifact-registry.js";
|
|
6
|
+
import { loadAgentWeaverSettings, updateWebUiSettings } from "../../runtime/settings.js";
|
|
6
7
|
import { InteractiveSessionController } from "../controller.js";
|
|
7
8
|
import { startWebServer, } from "./server.js";
|
|
8
9
|
function actionId(action) {
|
|
@@ -16,6 +17,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
16
17
|
let shuttingDown = false;
|
|
17
18
|
let activeScopeKey = options.scopeKey;
|
|
18
19
|
let artifactRestoreGeneration = 0;
|
|
20
|
+
let webUiSettings = loadAgentWeaverSettings().webUi;
|
|
19
21
|
const artifactCatalogProvider = webOptions.getArtifactCatalog ?? ((input) => {
|
|
20
22
|
const explorerScopeKey = controller.getViewModel().artifactExplorer.scopeKey;
|
|
21
23
|
const requestedScopeKey = input?.scopeKey;
|
|
@@ -26,7 +28,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
26
28
|
});
|
|
27
29
|
});
|
|
28
30
|
function snapshot() {
|
|
29
|
-
return { type: "snapshot", viewModel: controller.getViewModel() };
|
|
31
|
+
return { type: "snapshot", viewModel: controller.getViewModel(), settings: webUiSettings };
|
|
30
32
|
}
|
|
31
33
|
function sendError(client, message, id) {
|
|
32
34
|
const event = { type: "error", message, ...(id ? { actionId: id } : {}) };
|
|
@@ -68,33 +70,34 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
68
70
|
try {
|
|
69
71
|
const catalog = await artifactCatalogProvider({
|
|
70
72
|
scopeKey,
|
|
71
|
-
...(candidates.length === 1 && preferredRunId ? { runId: preferredRunId, runIds: candidates } : {}),
|
|
72
|
-
...(candidates.length > 1 ? { runIds: candidates } : {}),
|
|
73
73
|
});
|
|
74
74
|
if (!catalog || catalog.scopeKey !== scopeKey) {
|
|
75
75
|
return { runId: preferredRunId };
|
|
76
76
|
}
|
|
77
|
+
const markdownArtifactCount = catalog.items.filter((item) => item.scopeKey === scopeKey && item.kind === "markdown").length;
|
|
77
78
|
if (candidates.length === 0) {
|
|
78
79
|
return {
|
|
79
80
|
runId: null,
|
|
80
|
-
artifactCount:
|
|
81
|
+
artifactCount: markdownArtifactCount,
|
|
81
82
|
};
|
|
82
83
|
}
|
|
83
84
|
const matchingRunIds = candidates.filter((candidate) => (catalog.items.some((item) => item.scopeKey === scopeKey && item.runId === candidate && item.kind === "markdown")));
|
|
84
85
|
if (matchingRunIds.length > 0) {
|
|
85
|
-
const matchingRunIdSet = new Set(matchingRunIds);
|
|
86
86
|
return {
|
|
87
87
|
runId: matchingRunIds[0] ?? preferredRunId,
|
|
88
88
|
...(matchingRunIds.length > 1 ? { runIds: matchingRunIds } : {}),
|
|
89
|
-
artifactCount:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
artifactCount: markdownArtifactCount,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (markdownArtifactCount > 0) {
|
|
93
|
+
return {
|
|
94
|
+
runId: null,
|
|
95
|
+
artifactCount: markdownArtifactCount,
|
|
93
96
|
};
|
|
94
97
|
}
|
|
95
98
|
return {
|
|
96
99
|
runId: preferredRunId,
|
|
97
|
-
artifactCount:
|
|
100
|
+
artifactCount: markdownArtifactCount,
|
|
98
101
|
};
|
|
99
102
|
}
|
|
100
103
|
catch {
|
|
@@ -113,6 +116,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
113
116
|
...(artifactCount !== undefined ? { artifactCount } : {}),
|
|
114
117
|
open: !controller.hasActiveInput(),
|
|
115
118
|
});
|
|
119
|
+
await controller.refreshGitWorkspace();
|
|
116
120
|
}
|
|
117
121
|
async function restoreArtifactExplorerFromScope(scopeKey) {
|
|
118
122
|
const generation = ++artifactRestoreGeneration;
|
|
@@ -223,6 +227,83 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
223
227
|
controller.closeArtifactExplorer();
|
|
224
228
|
return;
|
|
225
229
|
}
|
|
230
|
+
if (action.type === "autoFlow.selectPreset") {
|
|
231
|
+
controller.selectAutoFlowPreset(action.preset);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (action.type === "autoFlow.loadConfig") {
|
|
235
|
+
controller.loadAutoFlowConfig(action.name, action.flowId);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (action.type === "autoFlow.save") {
|
|
239
|
+
controller.saveAutoFlowConfig(action.flowId, action.name, action.location);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (action.type === "autoFlow.reset") {
|
|
243
|
+
controller.resetAutoFlowConfig(action.flowId);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (action.type === "autoFlow.toggleBlock") {
|
|
247
|
+
controller.toggleAutoFlowBlock(action.flowId, action.blockId, action.enabled, action.slotId);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (action.type === "autoFlow.updateParam") {
|
|
251
|
+
controller.updateAutoFlowParameter(action.flowId, action.blockId, action.paramName, action.value, action.slotId);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (action.type === "autoFlow.insertBlock") {
|
|
255
|
+
controller.insertAutoFlowBlock(action.flowId, action.slotId, action.blockId);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (action.type === "autoFlow.removeBlock") {
|
|
259
|
+
controller.removeAutoFlowBlock(action.flowId, action.slotId, action.blockId);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (action.type === "git.refresh") {
|
|
263
|
+
await controller.refreshGitWorkspace();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (action.type === "git.createBranch") {
|
|
267
|
+
await controller.createGitBranch(action.branchName);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (action.type === "git.checkout") {
|
|
271
|
+
await controller.checkoutGitBranch(action.branchName);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (action.type === "git.fetch") {
|
|
275
|
+
await controller.fetchGitWorkspace();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (action.type === "git.pullFfOnly") {
|
|
279
|
+
await controller.pullGitWorkspaceFfOnly();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (action.type === "git.stage") {
|
|
283
|
+
await controller.stageGitPaths(action.paths);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (action.type === "git.unstage") {
|
|
287
|
+
await controller.unstageGitPaths(action.paths);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (action.type === "git.updateCommitMessage") {
|
|
291
|
+
controller.updateGitCommitMessage(action.message);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (action.type === "git.commit") {
|
|
295
|
+
await controller.commitGitChanges(action.paths, action.message);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (action.type === "git.push") {
|
|
299
|
+
await controller.pushGitWorkspace();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (action.type === "settings.update") {
|
|
303
|
+
webUiSettings = updateWebUiSettings(action.settings);
|
|
304
|
+
server?.broadcast(snapshot());
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
226
307
|
if (action.type === "help.toggle") {
|
|
227
308
|
controller.showHelp(action.visible ?? !controller.getViewModel().helpVisible);
|
|
228
309
|
return;
|
|
@@ -253,7 +334,9 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
253
334
|
}
|
|
254
335
|
server?.broadcast(snapshot());
|
|
255
336
|
});
|
|
256
|
-
void
|
|
337
|
+
void controller.refreshGitWorkspace().catch((error) => {
|
|
338
|
+
controller.appendLog(`Git workspace refresh failed: ${error.message}`);
|
|
339
|
+
}).then(() => startWebServer({
|
|
257
340
|
...(webOptions.noOpen !== undefined ? { noOpen: webOptions.noOpen } : {}),
|
|
258
341
|
...(webOptions.host !== undefined ? { host: webOptions.host } : {}),
|
|
259
342
|
...(webOptions.auth !== undefined ? { auth: webOptions.auth } : {}),
|
|
@@ -263,6 +346,8 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
263
346
|
},
|
|
264
347
|
...(webOptions.openBrowser ? { openBrowser: webOptions.openBrowser } : {}),
|
|
265
348
|
getArtifactCatalog: (input) => artifactCatalogProvider(input),
|
|
349
|
+
gitService: controller.getGitService(),
|
|
350
|
+
getGitWorkspaceSnapshot: () => controller.getGitWorkspaceSnapshot(),
|
|
266
351
|
onClientAction: (action, client) => {
|
|
267
352
|
void dispatch(action, client);
|
|
268
353
|
},
|
|
@@ -272,7 +357,7 @@ export function createWebInteractiveSession(options, webOptions = {}) {
|
|
|
272
357
|
onExitRequested: () => {
|
|
273
358
|
options.onExit();
|
|
274
359
|
},
|
|
275
|
-
}).then((started) => {
|
|
360
|
+
})).then((started) => {
|
|
276
361
|
if (shuttingDown) {
|
|
277
362
|
void started.close().catch((error) => {
|
|
278
363
|
process.stderr.write(`Failed to close Web UI server: ${error.message}\n`);
|