wave-code 0.17.0 → 0.17.2

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.
Files changed (59) hide show
  1. package/dist/acp/agent.d.ts +1 -0
  2. package/dist/acp/agent.d.ts.map +1 -1
  3. package/dist/acp/agent.js +116 -1
  4. package/dist/components/ChatInterface.d.ts.map +1 -1
  5. package/dist/components/ChatInterface.js +5 -2
  6. package/dist/components/InputBox.d.ts +2 -0
  7. package/dist/components/InputBox.d.ts.map +1 -1
  8. package/dist/components/InputBox.js +29 -8
  9. package/dist/components/LoadingIndicator.d.ts +2 -1
  10. package/dist/components/LoadingIndicator.d.ts.map +1 -1
  11. package/dist/components/LoadingIndicator.js +2 -2
  12. package/dist/components/QueuedMessageList.d.ts.map +1 -1
  13. package/dist/components/QueuedMessageList.js +10 -10
  14. package/dist/components/StatusLine.d.ts +2 -0
  15. package/dist/components/StatusLine.d.ts.map +1 -1
  16. package/dist/components/StatusLine.js +6 -6
  17. package/dist/components/TaskList.d.ts +3 -0
  18. package/dist/components/TaskList.d.ts.map +1 -1
  19. package/dist/components/TaskList.js +171 -28
  20. package/dist/components/TaskNotificationMessage.d.ts.map +1 -1
  21. package/dist/components/TaskNotificationMessage.js +1 -0
  22. package/dist/components/WorkflowManager.d.ts +6 -0
  23. package/dist/components/WorkflowManager.d.ts.map +1 -0
  24. package/dist/components/WorkflowManager.js +102 -0
  25. package/dist/constants/commands.d.ts.map +1 -1
  26. package/dist/constants/commands.js +6 -0
  27. package/dist/contexts/useChat.d.ts +8 -1
  28. package/dist/contexts/useChat.d.ts.map +1 -1
  29. package/dist/contexts/useChat.js +68 -4
  30. package/dist/hooks/useInputManager.d.ts +2 -0
  31. package/dist/hooks/useInputManager.d.ts.map +1 -1
  32. package/dist/hooks/useInputManager.js +22 -13
  33. package/dist/managers/inputHandlers.d.ts.map +1 -1
  34. package/dist/managers/inputHandlers.js +6 -3
  35. package/dist/managers/inputReducer.d.ts +10 -0
  36. package/dist/managers/inputReducer.d.ts.map +1 -1
  37. package/dist/managers/inputReducer.js +41 -4
  38. package/dist/print-cli.d.ts.map +1 -1
  39. package/dist/print-cli.js +3 -31
  40. package/dist/reducers/workflowManagerReducer.d.ts +41 -0
  41. package/dist/reducers/workflowManagerReducer.d.ts.map +1 -0
  42. package/dist/reducers/workflowManagerReducer.js +100 -0
  43. package/package.json +2 -2
  44. package/src/acp/agent.ts +137 -1
  45. package/src/components/ChatInterface.tsx +10 -1
  46. package/src/components/InputBox.tsx +43 -3
  47. package/src/components/LoadingIndicator.tsx +4 -1
  48. package/src/components/QueuedMessageList.tsx +7 -3
  49. package/src/components/StatusLine.tsx +28 -16
  50. package/src/components/TaskList.tsx +213 -19
  51. package/src/components/TaskNotificationMessage.tsx +1 -0
  52. package/src/components/WorkflowManager.tsx +320 -0
  53. package/src/constants/commands.ts +6 -0
  54. package/src/contexts/useChat.tsx +83 -4
  55. package/src/hooks/useInputManager.ts +25 -13
  56. package/src/managers/inputHandlers.ts +5 -4
  57. package/src/managers/inputReducer.ts +54 -6
  58. package/src/print-cli.ts +3 -37
  59. package/src/reducers/workflowManagerReducer.ts +143 -0
@@ -1,37 +1,180 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
2
3
  import { useChat } from "../contexts/useChat.js";
3
- import { Box, Text } from "ink";
4
+ import { Box, Text, useStdout } from "ink";
4
5
  import { useTasks } from "../hooks/useTasks.js";
6
+ const RECENTLY_COMPLETED_TTL_MS = 30000;
7
+ const AUTO_HIDE_DELAY_MS = 5000;
8
+ export const getStatusIcon = (status) => {
9
+ switch (status) {
10
+ case "pending":
11
+ return _jsx(Text, { color: "gray", children: "\u25A1" });
12
+ case "in_progress":
13
+ return _jsx(Text, { color: "yellow", children: "\u25A0" });
14
+ case "completed":
15
+ return _jsx(Text, { color: "green", children: "\u2713" });
16
+ case "deleted":
17
+ return _jsx(Text, { color: "red", children: "\u2715" });
18
+ default:
19
+ return _jsx(Text, { color: "gray", children: "?" });
20
+ }
21
+ };
22
+ function byIdAsc(a, b) {
23
+ const aNum = parseInt(a.id, 10);
24
+ const bNum = parseInt(b.id, 10);
25
+ if (!isNaN(aNum) && !isNaN(bNum)) {
26
+ return aNum - bNum;
27
+ }
28
+ return a.id.localeCompare(b.id);
29
+ }
30
+ export function sortTasksByPriority(tasks, completionTimestamps, now, needsTruncation) {
31
+ if (!needsTruncation) {
32
+ // No truncation needed — sort by ID for stable ordering
33
+ return [...tasks].sort(byIdAsc);
34
+ }
35
+ // When truncation is needed, prioritize:
36
+ // recently completed > in_progress > pending (unblocked first) > older completed > deleted
37
+ const recentCompleted = [];
38
+ const olderCompleted = [];
39
+ for (const task of tasks.filter((t) => t.status === "completed")) {
40
+ const ts = completionTimestamps.get(task.id);
41
+ if (ts && now - ts < RECENTLY_COMPLETED_TTL_MS) {
42
+ recentCompleted.push(task);
43
+ }
44
+ else {
45
+ olderCompleted.push(task);
46
+ }
47
+ }
48
+ recentCompleted.sort(byIdAsc);
49
+ olderCompleted.sort(byIdAsc);
50
+ const inProgress = tasks
51
+ .filter((t) => t.status === "in_progress")
52
+ .sort(byIdAsc);
53
+ const unresolvedTaskIds = new Set(tasks.filter((t) => t.status !== "completed").map((t) => t.id));
54
+ const pending = tasks
55
+ .filter((t) => t.status === "pending")
56
+ .sort((a, b) => {
57
+ const aBlocked = a.blockedBy.some((id) => unresolvedTaskIds.has(id));
58
+ const bBlocked = b.blockedBy.some((id) => unresolvedTaskIds.has(id));
59
+ if (aBlocked !== bBlocked)
60
+ return aBlocked ? 1 : -1;
61
+ return byIdAsc(a, b);
62
+ });
63
+ const deleted = tasks.filter((t) => t.status === "deleted").sort(byIdAsc);
64
+ return [
65
+ ...recentCompleted,
66
+ ...inProgress,
67
+ ...pending,
68
+ ...olderCompleted,
69
+ ...deleted,
70
+ ];
71
+ }
72
+ function getDisplayLimit(rows) {
73
+ const available = rows ?? 24;
74
+ return available <= 10 ? 0 : Math.min(10, Math.max(3, available - 14));
75
+ }
5
76
  export const TaskList = () => {
6
77
  const tasks = useTasks();
7
78
  const { isTaskListVisible } = useChat();
8
- if (tasks.length === 0 || !isTaskListVisible) {
9
- return null;
79
+ const { stdout } = useStdout();
80
+ const completionTimestampsRef = React.useRef(new Map());
81
+ const previousCompletedIdsRef = React.useRef(null);
82
+ const autoHideTimerRef = React.useRef(null);
83
+ const [autoHidden, setAutoHidden] = React.useState(() => {
84
+ // If all tasks are already completed on mount (e.g. session restore),
85
+ // start hidden immediately instead of flashing for 5 seconds.
86
+ const active = tasks.filter((t) => t.status !== "deleted");
87
+ return active.length > 0 && active.every((t) => t.status === "completed");
88
+ });
89
+ const [, forceUpdate] = React.useState(0);
90
+ const now = Date.now();
91
+ const activeTasks = tasks.filter((t) => t.status !== "deleted");
92
+ // Track completion timestamps: only set when a task newly transitions to completed
93
+ if (previousCompletedIdsRef.current === null) {
94
+ previousCompletedIdsRef.current = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
10
95
  }
11
- const getStatusIcon = (status) => {
12
- switch (status) {
13
- case "pending":
14
- return _jsx(Text, { color: "gray", children: "\u25A1" });
15
- case "in_progress":
16
- return _jsx(Text, { color: "yellow", children: "\u25A0" });
17
- case "completed":
18
- return _jsx(Text, { color: "green", children: "\u2713" });
19
- case "deleted":
20
- return _jsx(Text, { color: "red", children: "\u2715" });
21
- default:
22
- return _jsx(Text, { color: "gray", children: "?" });
96
+ const currentCompletedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
97
+ for (const id of currentCompletedIds) {
98
+ if (!previousCompletedIdsRef.current.has(id)) {
99
+ completionTimestampsRef.current.set(id, now);
23
100
  }
24
- };
25
- return (_jsx(Box, { flexDirection: "column", children: tasks.map((task) => {
26
- const isDimmed = task.status === "completed" || task.status === "deleted";
27
- const isBlocked = task.blockedBy && task.blockedBy.length > 0;
28
- const blockingTaskIds = isBlocked
29
- ? task.blockedBy.map((id) => `#${id}`)
30
- : [];
31
- const blockedByText = isBlocked && blockingTaskIds.length > 0
32
- ? ` (Blocked by: ${blockingTaskIds.join(", ")})`
33
- : "";
34
- const fullText = `${task.subject}${blockedByText}`;
35
- return (_jsxs(Box, { gap: 1, children: [getStatusIcon(task.status), _jsx(Text, { dimColor: isDimmed, children: fullText })] }, task.id));
36
- }) }));
101
+ }
102
+ for (const id of completionTimestampsRef.current.keys()) {
103
+ if (!currentCompletedIds.has(id)) {
104
+ completionTimestampsRef.current.delete(id);
105
+ }
106
+ }
107
+ previousCompletedIdsRef.current = currentCompletedIds;
108
+ // Schedule re-render when the next recent completion expires
109
+ React.useEffect(() => {
110
+ if (completionTimestampsRef.current.size === 0)
111
+ return;
112
+ const currentNow = Date.now();
113
+ let earliestExpiry = Infinity;
114
+ for (const ts of completionTimestampsRef.current.values()) {
115
+ const expiry = ts + RECENTLY_COMPLETED_TTL_MS;
116
+ if (expiry > currentNow && expiry < earliestExpiry) {
117
+ earliestExpiry = expiry;
118
+ }
119
+ }
120
+ if (earliestExpiry === Infinity)
121
+ return;
122
+ const timer = setTimeout(() => forceUpdate((n) => n + 1), earliestExpiry - currentNow);
123
+ return () => clearTimeout(timer);
124
+ }, [tasks]);
125
+ // Auto-hide logic: when all active tasks are completed
126
+ const allCompleted = activeTasks.length > 0 &&
127
+ activeTasks.every((t) => t.status === "completed");
128
+ React.useEffect(() => {
129
+ if (allCompleted && !autoHidden) {
130
+ autoHideTimerRef.current = setTimeout(() => {
131
+ setAutoHidden(true);
132
+ }, AUTO_HIDE_DELAY_MS);
133
+ }
134
+ if (!allCompleted && autoHidden) {
135
+ setAutoHidden(false);
136
+ }
137
+ return () => {
138
+ if (autoHideTimerRef.current) {
139
+ clearTimeout(autoHideTimerRef.current);
140
+ autoHideTimerRef.current = null;
141
+ }
142
+ };
143
+ }, [allCompleted, autoHidden]);
144
+ if (tasks.length === 0 || !isTaskListVisible || autoHidden) {
145
+ return null;
146
+ }
147
+ const displayLimit = getDisplayLimit(stdout?.rows);
148
+ const needsTruncation = tasks.length > displayLimit;
149
+ const sorted = sortTasksByPriority(tasks, completionTimestampsRef.current, now, needsTruncation);
150
+ const displayed = displayLimit > 0 ? sorted.slice(0, displayLimit) : [];
151
+ const hidden = displayLimit > 0 ? sorted.slice(displayLimit) : sorted;
152
+ const doneCount = tasks.filter((t) => t.status === "completed").length;
153
+ const inProgressCount = tasks.filter((t) => t.status === "in_progress").length;
154
+ const openCount = tasks.filter((t) => t.status === "pending").length;
155
+ // Summary parts for hidden tasks
156
+ const hiddenInProgress = hidden.filter((t) => t.status === "in_progress").length;
157
+ const hiddenPending = hidden.filter((t) => t.status === "pending").length;
158
+ const hiddenCompleted = hidden.filter((t) => t.status === "completed").length;
159
+ const summaryParts = [];
160
+ if (hiddenInProgress > 0)
161
+ summaryParts.push(`${hiddenInProgress} in progress`);
162
+ if (hiddenPending > 0)
163
+ summaryParts.push(`${hiddenPending} pending`);
164
+ if (hiddenCompleted > 0)
165
+ summaryParts.push(`${hiddenCompleted} completed`);
166
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [tasks.length, " tasks (", doneCount, " done, ", inProgressCount, " in progress,", " ", openCount, " open)"] }), displayed.map((task) => {
167
+ const isDimmed = task.status === "completed" || task.status === "deleted";
168
+ const unresolvedTaskIds = new Set(tasks.filter((t) => t.status !== "completed").map((t) => t.id));
169
+ const isBlocked = task.blockedBy &&
170
+ task.blockedBy.some((id) => unresolvedTaskIds.has(id));
171
+ const blockingTaskIds = isBlocked
172
+ ? task.blockedBy.map((id) => `#${id}`)
173
+ : [];
174
+ const blockedByText = isBlocked && blockingTaskIds.length > 0
175
+ ? ` (Blocked by: ${blockingTaskIds.join(", ")})`
176
+ : "";
177
+ const fullText = `${task.subject}${blockedByText}`;
178
+ return (_jsxs(Box, { gap: 1, children: [getStatusIcon(task.status), _jsx(Text, { dimColor: isDimmed, wrap: "truncate-end", children: fullText })] }, task.id));
179
+ }), displayLimit > 0 && hidden.length > 0 && (_jsxs(Text, { dimColor: true, children: [" \u2026 +", summaryParts.join(", ")] }))] }));
37
180
  };
@@ -1 +1 @@
1
- {"version":3,"file":"TaskNotificationMessage.d.ts","sourceRoot":"","sources":["../../src/components/TaskNotificationMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,qBAAqB,CAAC;CAC9B;AAQD,eAAO,MAAM,uBAAuB,GAAI,YAErC,4BAA4B,4CAW9B,CAAC"}
1
+ {"version":3,"file":"TaskNotificationMessage.d.ts","sourceRoot":"","sources":["../../src/components/TaskNotificationMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,qBAAqB,CAAC;CAC9B;AASD,eAAO,MAAM,uBAAuB,GAAI,YAErC,4BAA4B,4CAW9B,CAAC"}
@@ -4,6 +4,7 @@ const statusColor = {
4
4
  completed: "green",
5
5
  failed: "red",
6
6
  killed: "yellow",
7
+ aborted: "gray",
7
8
  };
8
9
  export const TaskNotificationMessage = ({ block, }) => {
9
10
  const color = statusColor[block.status];
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ export interface WorkflowManagerProps {
3
+ onCancel: () => void;
4
+ }
5
+ export declare const WorkflowManager: React.FC<WorkflowManagerProps>;
6
+ //# sourceMappingURL=WorkflowManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkflowManager.d.ts","sourceRoot":"","sources":["../../src/components/WorkflowManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AASrD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAmCD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAiR1D,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useEffect, useReducer } from "react";
3
+ import { Box, Text, useInput } from "ink";
4
+ import { useChat } from "../contexts/useChat.js";
5
+ import { workflowManagerReducer, } from "../reducers/workflowManagerReducer.js";
6
+ const statusColor = (status) => {
7
+ switch (status) {
8
+ case "running":
9
+ return "green";
10
+ case "completed":
11
+ return "blue";
12
+ case "failed":
13
+ case "aborted":
14
+ return "red";
15
+ case "paused":
16
+ return "yellow";
17
+ }
18
+ };
19
+ const formatDuration = (ms) => {
20
+ if (ms < 1000)
21
+ return `${ms}ms`;
22
+ if (ms < 60000)
23
+ return `${Math.round(ms / 1000)}s`;
24
+ const minutes = Math.floor(ms / 60000);
25
+ const seconds = Math.round((ms % 60000) / 1000);
26
+ return `${minutes}m ${seconds}s`;
27
+ };
28
+ const formatTime = (timestamp) => {
29
+ return new Date(timestamp).toLocaleTimeString();
30
+ };
31
+ const formatTokens = (tokens) => {
32
+ if (tokens < 1000)
33
+ return `${tokens}`;
34
+ return `${(tokens / 1000).toFixed(1)}k`;
35
+ };
36
+ export const WorkflowManager = ({ onCancel, }) => {
37
+ const { workflowRuns, stopWorkflowRun } = useChat();
38
+ const MAX_VISIBLE_ITEMS = 3;
39
+ const [state, dispatch] = useReducer(workflowManagerReducer, {
40
+ runs: [],
41
+ selectedIndex: 0,
42
+ viewMode: "list",
43
+ detailRunId: null,
44
+ pendingEffect: null,
45
+ });
46
+ // Handle pending effects
47
+ useEffect(() => {
48
+ if (!state.pendingEffect)
49
+ return;
50
+ const effect = state.pendingEffect;
51
+ dispatch({ type: "CLEAR_PENDING_EFFECT" });
52
+ switch (effect.type) {
53
+ case "CANCEL":
54
+ onCancel();
55
+ break;
56
+ case "STOP_RUN":
57
+ stopWorkflowRun(effect.runId);
58
+ break;
59
+ }
60
+ }, [state.pendingEffect, onCancel, stopWorkflowRun]);
61
+ const { runs, selectedIndex, viewMode, detailRunId } = state;
62
+ // Sync workflowRuns from context
63
+ useEffect(() => {
64
+ dispatch({ type: "SET_RUNS", runs: workflowRuns });
65
+ }, [workflowRuns]);
66
+ useInput((input, key) => {
67
+ dispatch({ type: "HANDLE_KEY", input, key });
68
+ });
69
+ // Detail view
70
+ if (viewMode === "detail" && detailRunId) {
71
+ const run = runs.find((r) => r.runId === detailRunId);
72
+ if (!run) {
73
+ dispatch({ type: "RESET_DETAIL" });
74
+ return null;
75
+ }
76
+ const elapsed = run.endTime
77
+ ? run.endTime - run.startTime
78
+ : Date.now() - run.startTime;
79
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Workflow Details: ", run.meta.name] }) }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Run ID:" }), " ", run.runId] }) }), run.meta.description && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Description:" }), " ", run.meta.description] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", _jsx(Text, { color: statusColor(run.status), children: run.status })] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(run.startTime), run.endTime && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Ended:" }), " ", formatTime(run.endTime)] })), " | ", _jsx(Text, { color: "blue", children: "Duration:" }), " ", formatDuration(elapsed)] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Agents:" }), " ", run.totalAgents, " ", " | ", _jsx(Text, { color: "blue", children: "Tokens:" }), " ", formatTokens(run.totalTokens)] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Script:" }), " ", run.scriptPath] }) }), run.error && (_jsx(Box, { children: _jsxs(Text, { color: "red", children: [_jsx(Text, { color: "blue", children: "Error:" }), " ", run.error] }) }))] }), run.phases.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Phases:" }), run.phases.map((phase, i) => (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: phase.title }), " — ", phase.agentCount, " agents | ", formatTokens(phase.tokens), " ", "tokens | ", formatDuration(phase.elapsed)] }) }, i)))] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [run.status === "running" ? "k to stop · " : "", "Esc back"] }) })] }));
80
+ }
81
+ // Empty state
82
+ if (runs.length === 0) {
83
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Workflows" }), _jsx(Text, { children: "No workflow runs found" }), _jsx(Text, { dimColor: true, children: "Press Escape to close" })] }));
84
+ }
85
+ // List view
86
+ const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, runs.length - MAX_VISIBLE_ITEMS)));
87
+ const visibleRuns = runs.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
88
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "Workflows" }) }), _jsx(Text, { dimColor: true, children: "Select a run to view details" }), _jsx(Box, { flexDirection: "column", children: visibleRuns.map((run, index) => {
89
+ const actualIndex = startIndex + index;
90
+ const isSelected = actualIndex === selectedIndex;
91
+ const elapsed = run.endTime
92
+ ? run.endTime - run.startTime
93
+ : Date.now() - run.startTime;
94
+ const phaseText = run.phases.map((p) => p.title).join(" → ");
95
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", actualIndex + 1, ". ", run.runId.slice(0, 8), " ", run.meta.name, _jsxs(Text, { color: statusColor(run.status), children: [" (", run.status, ")"] })] }), _jsxs(Text, { color: isSelected ? "black" : "gray", backgroundColor: isSelected ? "cyan" : undefined, children: [" ", run.totalAgents, " agents \u00B7 ", formatTokens(run.totalTokens), " ", "tokens \u00B7 ", formatDuration(elapsed)] }), phaseText && (_jsxs(Text, { color: isSelected ? "black" : "gray", backgroundColor: isSelected ? "cyan" : undefined, children: [" ", run.phases.map((p, pi) => (_jsxs(React.Fragment, { children: [pi > 0 && " → ", _jsx(Text, { color: isSelected
96
+ ? "black"
97
+ : pi === run.phases.length - 1 &&
98
+ run.status === "running"
99
+ ? "green"
100
+ : undefined, backgroundColor: isSelected ? "cyan" : undefined, children: p.title })] }, pi)))] })), isSelected && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [_jsx(Text, { color: "blue", children: "Script:" }), " ", run.scriptPath] }) }))] }, run.runId));
101
+ }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["\u2191/\u2193 select \u00B7 Enter detail \u00B7", " ", runs[selectedIndex]?.status === "running" ? "k stop · " : "", "Esc close"] }) })] }));
102
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/constants/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,kBAAkB,EAAE,YAAY,EA8D5C,CAAC"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/constants/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,kBAAkB,EAAE,YAAY,EAoE5C,CAAC"}
@@ -59,4 +59,10 @@ export const AVAILABLE_COMMANDS = [
59
59
  description: "Clear SSO authentication",
60
60
  handler: () => { }, // Handler here won't be used, actual processing is in the hook
61
61
  },
62
+ {
63
+ id: "workflows",
64
+ name: "workflows",
65
+ description: "View and manage workflow runs",
66
+ handler: () => { }, // Handler here won't be used, actual processing is in the hook
67
+ },
62
68
  ];
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { Message, McpServerStatus, BackgroundTask, Task, SlashCommand, PermissionDecision, PermissionMode, QueuedMessage } from "wave-agent-sdk";
2
+ import type { Message, McpServerStatus, BackgroundTask, Task, SlashCommand, PermissionDecision, PermissionMode, QueuedMessage, WorkflowRun } from "wave-agent-sdk";
3
3
  import { BaseAppProps } from "../types.js";
4
4
  export interface ChatContextType {
5
5
  messages: Message[];
@@ -17,6 +17,8 @@ export interface ChatContextType {
17
17
  }>, longTextMap?: Record<string, string>) => Promise<void>;
18
18
  askBtw: (question: string) => Promise<string>;
19
19
  abortMessage: () => void;
20
+ recallQueuedMessage: () => QueuedMessage | null;
21
+ removeQueuedMessageById: (id: string) => boolean;
20
22
  latestTotalTokens: number;
21
23
  maxInputTokens: number;
22
24
  currentModel: string;
@@ -27,6 +29,8 @@ export interface ChatContextType {
27
29
  connectMcpServer: (serverName: string) => Promise<boolean>;
28
30
  disconnectMcpServer: (serverName: string) => Promise<boolean>;
29
31
  backgroundTasks: BackgroundTask[];
32
+ workflowRuns: WorkflowRun[];
33
+ stopWorkflowRun: (runId: string) => void;
30
34
  tasks: Task[];
31
35
  getBackgroundTaskOutput: (taskId: string) => {
32
36
  stdout: string;
@@ -67,6 +71,9 @@ export interface ChatContextType {
67
71
  workdir?: string;
68
72
  recreateAgent: () => void;
69
73
  triggerWorktreeRemoveHook: (worktreePath: string) => Promise<void>;
74
+ isGoalActive: boolean;
75
+ goalElapsed?: string;
76
+ isGoalEvaluating: boolean;
70
77
  }
71
78
  export declare const useChat: () => ChatContextType;
72
79
  export interface ChatProviderProps extends BaseAppProps {
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
@@ -50,10 +50,35 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
50
50
  const [currentModel, setCurrentModelState] = useState("");
51
51
  const [configuredModels, setConfiguredModels] = useState([]);
52
52
  const [queuedMessages, setQueuedMessages] = useState([]);
53
+ const [isGoalActive, setIsGoalActive] = useState(false);
54
+ const [goalElapsed, setGoalElapsed] = useState();
55
+ const [isGoalEvaluating, setIsGoalEvaluating] = useState(false);
56
+ const goalStartedAt = useRef(null);
57
+ // Update goal elapsed time every 30s while active
58
+ useEffect(() => {
59
+ if (!isGoalActive || goalStartedAt.current === null)
60
+ return;
61
+ const formatElapsed = (ms) => {
62
+ const minutes = Math.floor(ms / 60000);
63
+ if (minutes < 1)
64
+ return "<1m";
65
+ if (minutes < 60)
66
+ return `${minutes}m`;
67
+ const hours = Math.floor(minutes / 60);
68
+ const remainingMin = minutes % 60;
69
+ return `${hours}h${remainingMin}m`;
70
+ };
71
+ const update = () => setGoalElapsed(formatElapsed(Date.now() - goalStartedAt.current));
72
+ update();
73
+ const timer = setInterval(update, 30000);
74
+ return () => clearInterval(timer);
75
+ }, [isGoalActive]);
53
76
  // MCP State
54
77
  const [mcpServerStatuses, setMcpServerStatuses] = useState([]);
55
78
  // Background tasks state
56
79
  const [backgroundTasks, setBackgroundTasks] = useState([]);
80
+ // Workflow runs state
81
+ const [workflowRuns, setWorkflowRuns] = useState([]);
57
82
  // Tasks state
58
83
  const [tasks, setTasks] = useState([]);
59
84
  // Command state
@@ -126,11 +151,21 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
126
151
  onCompactionStateChange: (isCompactingState) => {
127
152
  setIsCompacting(isCompactingState);
128
153
  },
129
- onBackgroundTasksChange: (tasks) => {
154
+ onBackgroundTasksChange: async (tasks) => {
130
155
  setBackgroundTasks([...tasks]);
156
+ // Also refresh workflow runs since workflows are background tasks
157
+ const runs = await agentRef.current?.getWorkflowRuns();
158
+ if (runs)
159
+ setWorkflowRuns([...runs]);
131
160
  },
132
- onTasksChange: (tasks) => {
133
- setTasks([...tasks]);
161
+ onTasksChange: (newTasks) => {
162
+ setTasks((prev) => {
163
+ if (prev.length === newTasks.length &&
164
+ prev.every((t, i) => t.id === newTasks[i].id && t.status === newTasks[i].status)) {
165
+ return prev;
166
+ }
167
+ return [...newTasks];
168
+ });
134
169
  },
135
170
  onPermissionModeChange: (mode) => {
136
171
  setPermissionModeState(mode);
@@ -150,6 +185,19 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
150
185
  onQueuedMessagesChange: (messages) => {
151
186
  setQueuedMessages([...messages]);
152
187
  },
188
+ onGoalStateChange: (active, _condition, elapsed) => {
189
+ setIsGoalActive(active);
190
+ if (active) {
191
+ goalStartedAt.current = Date.now();
192
+ }
193
+ else {
194
+ goalStartedAt.current = null;
195
+ }
196
+ setGoalElapsed(elapsed);
197
+ },
198
+ onGoalEvaluating: (evaluating) => {
199
+ setIsGoalEvaluating(evaluating);
200
+ },
153
201
  };
154
202
  try {
155
203
  // Create the permission callback inside the try block to access showConfirmation
@@ -194,7 +242,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
194
242
  setIsCompacting(agent.isCompacting);
195
243
  setPermissionModeState(agent.getPermissionMode());
196
244
  setWorkingDirectory(agent.workingDirectory);
197
- setCurrentModelState(agent.getModelConfig().model);
245
+ setCurrentModelState(agent.getModelConfig().model || "");
198
246
  setConfiguredModels(agent.getConfiguredModels());
199
247
  setMaxInputTokens(agent.getMaxInputTokens());
200
248
  // Get initial MCP servers state
@@ -315,6 +363,12 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
315
363
  const abortMessage = useCallback(() => {
316
364
  agentRef.current?.abortMessage();
317
365
  }, []);
366
+ const recallQueuedMessage = useCallback(() => {
367
+ return agentRef.current?.recallQueuedMessage() ?? null;
368
+ }, []);
369
+ const removeQueuedMessageById = useCallback((id) => {
370
+ return agentRef.current?.removeQueuedMessageById(id) ?? false;
371
+ }, []);
318
372
  // Permission management methods
319
373
  const setPermissionMode = useCallback((mode) => {
320
374
  setPermissionModeState((prev) => {
@@ -344,6 +398,9 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
344
398
  return false;
345
399
  return agentRef.current.stopBackgroundTask(taskId);
346
400
  }, []);
401
+ const stopWorkflowRun = useCallback((runId) => {
402
+ agentRef.current?.stopWorkflowRun(runId);
403
+ }, []);
347
404
  const hasSlashCommand = useCallback((commandId) => {
348
405
  if (!agentRef.current)
349
406
  return false;
@@ -478,6 +535,8 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
478
535
  sendMessage,
479
536
  askBtw,
480
537
  abortMessage,
538
+ recallQueuedMessage,
539
+ removeQueuedMessageById,
481
540
  latestTotalTokens,
482
541
  maxInputTokens,
483
542
  currentModel,
@@ -489,6 +548,8 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
489
548
  connectMcpServer,
490
549
  disconnectMcpServer,
491
550
  backgroundTasks,
551
+ workflowRuns,
552
+ stopWorkflowRun,
492
553
  tasks,
493
554
  getBackgroundTaskOutput,
494
555
  stopBackgroundTask,
@@ -515,6 +576,9 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
515
576
  workdir,
516
577
  recreateAgent,
517
578
  triggerWorktreeRemoveHook,
579
+ isGoalActive,
580
+ goalElapsed,
581
+ isGoalEvaluating,
518
582
  };
519
583
  return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
520
584
  };
@@ -22,6 +22,7 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
22
22
  showLoginCommand: boolean;
23
23
  showPluginManager: boolean;
24
24
  showModelSelector: boolean;
25
+ showWorkflowManager: boolean;
25
26
  permissionMode: PermissionMode;
26
27
  attachedImages: import("../managers/inputReducer.js").AttachedImage[];
27
28
  btwState: import("../managers/inputReducer.js").BtwState;
@@ -53,6 +54,7 @@ export declare const useInputManager: (callbacks?: Partial<InputManagerCallbacks
53
54
  setShowLoginCommand: (show: boolean) => void;
54
55
  setShowPluginManager: (show: boolean) => void;
55
56
  setShowModelSelector: (show: boolean) => void;
57
+ setShowWorkflowManager: (show: boolean) => void;
56
58
  setPermissionMode: (mode: PermissionMode) => void;
57
59
  setBtwState: (payload: Partial<import("../managers/inputReducer.js").BtwState>) => void;
58
60
  addImage: (imagePath: string, mimeType: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAGL,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,cAAc,EACd,WAAW,EAEZ,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;+BAkVA,MAAM;;;;;qCAoBA,MAAM;iCAIV,MAAM;;mCAQJ,MAAM;oCAK1C,MAAM;wCAQmC,MAAM;mCAIX,MAAM;mCAIN,MAAM;;sCAQH,MAAM;uCAK7C,MAAM;uCAMkC,WAAW;;iCASxD,MAAM;yCAcyC,OAAO;8BAIlB,OAAO;iCAIJ,OAAO;wBAIhB,OAAO;iCAIE,OAAO;gCAIR,OAAO;iCAIN,OAAO;iCAIP,OAAO;8BAK9C,cAAc;2BAQX,OAAO,CAAC,OAAO,6BAA6B,EAAE,QAAQ,CAAC;0BAM1B,MAAM,YAAY,MAAM;2BAIvB,MAAM;;;8BAatC,MAAM;;uCAyBP,MAAM;;yBAYJ,MAAM,OACR,GAAG,mBACS,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,gBACxD,MAAM,IAAI;yBAhHY,MAAM;kCAIG,MAAM;;CA0NxD,CAAC"}
1
+ {"version":3,"file":"useInputManager.d.ts","sourceRoot":"","sources":["../../src/hooks/useInputManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAGL,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,cAAc,EACd,WAAW,EAEZ,MAAM,gBAAgB,CAAC;AAGxB,eAAO,MAAM,eAAe,GAC1B,YAAW,OAAO,CAAC,qBAAqB,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;+BAqVA,MAAM;;;;;qCAoBA,MAAM;iCAIV,MAAM;;mCAQJ,MAAM;oCAK1C,MAAM;wCAQmC,MAAM;mCAIX,MAAM;mCAIN,MAAM;;sCAQH,MAAM;uCAK7C,MAAM;uCAMkC,WAAW;;iCASxD,MAAM;yCAcyC,OAAO;8BAIlB,OAAO;iCAIJ,OAAO;wBAIhB,OAAO;iCAIE,OAAO;gCAIR,OAAO;iCAIN,OAAO;iCAIP,OAAO;mCAIL,OAAO;8BAKhD,cAAc;2BAQX,OAAO,CAAC,OAAO,6BAA6B,EAAE,QAAQ,CAAC;0BAM1B,MAAM,YAAY,MAAM;2BAIvB,MAAM;;;8BAatC,MAAM;;uCA2BP,MAAM;;yBAYJ,MAAM,OACR,GAAG,mBACS,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,gBACxD,MAAM,IAAI;yBAtHY,MAAM;kCAIG,MAAM;;CAmOxD,CAAC"}